配色: 字号:
C++二叉树结构的建立与基本操作
2016-12-27 | 阅:  转:  |  分享 
  
C++二叉树结构的建立与基本操作



二叉树是数据结构中的树的一种特殊情况,有关二叉树的相关概念,这里不再赘述,如果不了解二叉树相关概念,建议先学习数据结构中的二叉树的知识点

准备数据

定义二叉树结构操作中需要用到的变量及数据等。





复制代码代码如下:





#defineMAXLEN20//最大长度

typedefcharDATA;//定义元素类型

structCBTType//定义二叉树结点类型

{

DATAdata;//元素数据

CBTTypeleft;//左子树结点指针

CBTTyperight;//右子树结点指针

};





定义二叉树结构数据元素的类型DATA以及二叉树结构的数据结构CBTType。结点的具体数据保存在一个姐都DATA中,而指针left用来指向左子树结点,指针right用来指向右子树结点



初始化二叉树

初始化二叉树,将一个结点设置为二叉树的根结点。





复制代码代码如下:





CBTTypeInitTree()

{

CBTTypenode;

if(node=newCBTType)//申请内存

{

cout<<"请先输入一个根节点数据:"<
cin>>node->data;

node->left=NULL;

node->right=NULL;

if(node!=NULL)//如果二叉树结点不为空

{

returnnode;

}else

{

returnNULL;

}

}

returnNULL;

}





首先申请一个结点,然后用户输入根结点的数据,并将左子树和右子树的指针置为空,即可完成二叉树的初始化工作。



查找结点



查找结点就是遍历二叉树中的每一个节点,逐个比较数据,当找到目标数据时将返回该数据所在结点的指针。





复制代码代码如下:





CBTTypeTreeFindNode(CBTTypetreeNode,DATAdata)

{

CBTTypeptr;

if(treeNode==NULL)

{

returnNULL;

}else

{

if(treeNode->data==data)

{

returntreeNode;

}

else//分别向左右子树查找

{

if(ptr=TreeFindNode(treeNode->left,data))//左子树递归查找

{

returnptr;

}

elseif(ptr=TreeFindNode(treeNode->right,data))//右子树递归查找

{

returnptr;

}

else

{

returnNULL;

}

}

}

}





输入参数treeNode为待查找的二叉树的根结点,输入参数data为待查找的结点数据。程序中首先判断根结点是否为空,然后根据数据判断是否为根结点,然后分别向左右子树进行查找,采用递归的方法进行查找,查找到该结点则返回结点对应的指针;如果全都查找不到,则返回NULL。



添加结点

添加结点就是在二叉树中添加结点数据,添加结点时除了要输入结点数据外,还需要指定其父结点,以及添加的结点作为左子树还是右子树。然后将该结点置为其父结点的左子树或者右子树。





复制代码代码如下:





voidAddTreeNode(CBTTypetreeNode)

{

CBTTypepnode,parent;

DATAdata;

charmenusel;

if(pnode=newCBTType)//分配内存

{

cout<<"输入二叉树结点数据:"<
cin>>pnode->data;

pnode->left=NULL;//设置左子树为空

pnode->right=NULL;//设置左子树为空

cout<<"输入该结点的父结点数据"<
cin>>data;

parent=TreeFindNode(treeNode,data);//查找父结点,获得结点指针

if(!parent)

{

cout<<"没有找到父结点"<
deletepnode;

return;

}

cout<<"1.添加该结点到左子树;2.添加该结点到右子树。请输入操作对应的数字。"<
do

{

cin>>menusel;

if(menusel==''1''||menusel==''2'')

{

switch(menusel)

{

case''1''://添加结点到左子树

if(parent->left)//左子树不为空

{

cout<<"左子树结点不为空"<
}

else

{

parent->left=pnode;

cout<<"数据添加成功!"<
}

break;

case''2''://添加结点到右子树

if(parent->right)//右子树不为空

{

cout<<"右子树结点不为空"<
}

else

{

parent->right=pnode;

cout<<"数据添加成功!"<
}

break;

default:

cout<<"子节点选择error!"<
break;

}

}

}while(menusel!=''1''&&menusel!=''2'');

}

}





输入参数treeNode为二叉树的根结点,传入根节点是为了方便查找父结点。程序中首先申请内存,然后由用户输入二叉树结点数据,并设置左右子树为空。接着指定其父结点,将其置为左子树或者右子树。



计算二叉树的深度

计算二叉树深度就是计算二叉树中结点的最大层数,这里往往需要采用递归算法来实现。





复制代码代码如下:





intTreeDepth(CBTTypetreeNode)

{

intdepleft,depright;

if(treeNode==NULL)

{

return0;//结点为空的时候,深度为0

}

else

{

depleft=TreeDepth(treeNode->left);//左子树深度(递归调用)

depright=TreeDepth(treeNode->right);//右子树深度(递归调用)

if(depleft)

{

return++depleft;

}

else

{

return++depright;

}

}

}





输入参数treeNode为待计算的二叉树的根结点。首先判断根节点是否为空,然后分别按照递归调用来计算左子树深度和右子树深度,从而完成整个二叉树深度的计算。



显示结点数据





复制代码代码如下:





voidShowNodeData(CBTTypetreeNode)

{

cout<data<<"\t";//直接输出结点数据

}





输入参数为需要显示的结点的指针。



清空二叉树

清空二叉树就是将二叉树变成一个空树,这里也需要使用递归算法来实现。





复制代码代码如下:





voidClearTree(CBTTypetreeNode)

{

if(treeNode)//判断当前树不为空

{

ClearTree(treeNode->left);//清空左子树

ClearTree(treeNode->right);//清空右子树

deletetreeNode;//释放当前结点所占用的内存

}

}





输入参数treeNode为待清空的二叉树的根节点。程序中按照递归的方法清空左子树和右子树以及根节点,释放结点占用的内存空间,从而完成清空操作。



遍历二叉树

遍历二叉树就是逐个查找二叉树中所有的结点,这里为了直观的显示查找的结果,将会按照查找的顺序,依次输出对应的结点。



按层遍历算法

按层遍历算法是最直观的算法。即:首先输出第一层即根结点,然后输出第一个结点的左右子数,也就是第二层……这样循环处理,就可以逐层遍历,一层一层按照从上到下,从左到右的顺序输出结点。





复制代码代码如下:





voidLevelTree(CBTTypetreeNode)

{

CBTTypep;

CBTTypeq[MAXLEN];//定义一个队列

inthead=0,tail=0;

if(treeNode)//如果队首指针不为空

{

tail=(tail+1)%MAXLEN;//计算循环队列队尾序号

q[tail]=treeNode;//二叉树根指针进入队列

while(head!=tail)

{

head=(head+1)%MAXLEN;//计算循环队列的队首序号

p=q[head];//获取队首元素

ShowNodeData(p);//输出队首元素

if(p->left!=NULL)//如果存在左子树

{

tail=(tail+1)%MAXLEN;//计算队列的队尾序号

q[tail]=p->left;//左子树入队

}

if(p->right!=NULL)//如果存在右子树

{

tail=(tail+1)%MAXLEN;//计算队列的队尾序号

q[tail]=p->right;//右子树入队

}

}

}

}





输入参数treeNode为需要遍历的二叉树的根结点,程序在整个处理过程中,首先从根节点开始,将每层的结点逐步进入循环队列,并且每次循环都是输出队首的一个结点数据,然后再使它的左右子树进入队列。如此循环直到队列中的所有的数据都输出完毕。





先序遍历算法

先序遍历算法就是先访问根节点,然后访问左子树,然后访问右子树。程序中可以按照递归的思想遍历左子树和右子树。





复制代码代码如下:





voidDLRTree(CBTTypetreeNode)

{

if(treeNode)

{

ShowNodeData(treeNode);//显示结点内容

DLRTree(treeNode->left);//显示左子树内容

DLRTree(treeNode->right);//显示右子树内容

}

}





中序遍历算法

先序遍历算法就是先访问左子树,然后访问根节点,然后访问右子树。程序中可以按照递归的思想遍历左子树和右子树。



复制代码代码如下:





voidLDRTree(CBTTypetreeNode)

{

if(treeNode)

{



LDRTree(treeNode->left);//显示左子树内容

ShowNodeData(treeNode);//显示结点内容

DLRTree(treeNode->right);//显示右子树内容

}

}





后序遍历算法

先序遍历算法就是先访问左子树,然后访问右子树,然后访问根节点。程序中可以按照递归的思想遍历左子树和右子树。



复制代码代码如下:





voidLRDTree(CBTTypetreeNode)

{

if(treeNode)

{

LRDTree(treeNode->left);//显示左子树内容

DLRTree(treeNode->right);//显示右子树内容

ShowNodeData(treeNode);//显示结点内容

}

}





完整代码示例操作:



在文件中加入头文件,然后包含上述所有函数,然后再写一个main函数即可:





复制代码代码如下:





#include

usingnamespacwww.visa158.comtd;

#defineMAXLEN20//最大长度

typedefcharDATA;//定义元素类型

structCBTType/定义二叉树结点类型

{

DATAdata;//元素数据

CBTTypeleft;//左子树结点指针

CBTTyperight;//右子树结点指针

};

/初始化二叉树/

CBTTypeInitTree()

{

CBTTypenode;

if(node=newCBTType)//申请内存

{

cout<<"请先输入一个根节点数据:"<
cin>>node->data;

node->left=NULL;

node->right=NULL;

if(node!=NULL)//如果二叉树结点不为空

{

returnnode;

}else

{

returnNULL;

}

}

returnNULL;

}

/查找结点/

CBTTypeTreeFindNode(CBTTypetreeNode,DATAdata)

{

CBTTypeptr;

if(treeNode==NULL)

{

returnNULL;

}else

{

if(treeNode->data==data)

{

returntreeNode;

}

else//分别向左右子树查找

{

if(ptr=TreeFindNode(treeNode->left,data))//左子树递归查找

{

returnptr;

}

elseif(ptr=TreeFindNode(treeNode->right,data))//右子树递归查找

{

returnptr;

}

else

{

returnNULL;

}

}

}

}

/添加结点/

voidAddTreeNode(CBTTypetreeNode)

{

CBTTypepnode,parent;

DATAdata;

charwww.hunanwang.netmenusel;

if(pnode=newCBTType)//分配内存

{

cout<<"输入二叉树结点数据:"<
cin>>pnode->data;

pnode->left=NULL;//设置左子树为空

pnode->right=NULL;//设置左子树为空

cout<<"输入该结点的父结点数据"<
cin>>data;

parent=TreeFindNode(treeNode,data);//查找父结点,获得结点指针

if(!parent)

{

cout<<"没有找到父结点"<
deletepnode;

return;

}

cout<<"1.添加该结点到左子树;2.添加该结点到右子树。请输入操作对应的数字。"<
do

{

cin>>menusel;

if(menusel==''1''||menusel==''2'')

{

switch(menusel)

{

case''1''://添加结点到左子树

if(parent->left)//左子树不为空

{

cout<<"左子树结点不为空"<
}

else

{

parent->left=pnode;

cout<<"数据添加成功!"<
}

break;

case''2''://添加结点到右子树

if(parent->right)//右子树不为空

{

cout<<"右子树结点不为空"<
}

else

{

parent->right=pnode;

cout<<"数据添加成功!"<
}

break;

default:

cout<<"子节点选择error!"<
break;

}

}

}while(menusel!=''1''&&menusel!=''2'');

}

}

/计算二叉树的深度/

intTreeDepth(CBTTypetreeNode)

{

intdepleft,depright;

if(treeNode==NULL)

{

return0;//结点为空的时候,深度为0

}

else

{

depleft=TreeDepth(treeNode->left);//左子树深度(递归调用)

depright=TreeDepth(treeNode->right);//右子树深度(递归调用)

if(depleft)

{

return++depleft;

}

else

{

return++depright;

}

}

}

/显示结点数据/

voidShowNodeData(CBTTypetreeNode)

{

cout<data<<"\t";//直接输出结点数据

}

/清空二叉树/

voidClearTree(CBTTypetreeNode)

{

if(treeNode)//判断当前树不为空

{

ClearTree(treeNode->left);//清空左子树

ClearTree(treeNode->right);//清空右子树

deletetreeNode;//释放当前结点所占用的内存

}

}

/按层遍历算法/

voidLevelTree(CBTTypetreeNode)

{

CBTTypep;

CBTTypeq[MAXLEN];//定义一个队列

inthead=0,tail=0;

if(treeNode)//如果队首指针不为空

{

tail=(tail+1)%MAXLEN;//计算循环队列队尾序号

q[tail]=treeNode;//二叉树根指针进入队列

while(head!=tail)

{

head=(head+1)%MAXLEN;//计算循环队列的队首序号

p=q[head];//获取队首元素

ShowNodeData(p);//输出队首元素

if(p->left!=NULL)//如果存在左子树

{

tail=(tail+1)%MAXLEN;//计算队列的队尾序号

q[tail]=p->left;//左子树入队

}

if(p->right!=NULL)//如果存在右子树

{

tail=(tail+1)%MAXLEN;//计算队列的队尾序号

q[tail]=p->right;//右子树入队

}

}

}

}

/先序遍历算法/

voidDLRTree(CBTTypetreeNode)

{

if(treeNode)

{

ShowNodeData(treeNode);//显示结点内容

DLRTree(treeNode->left);//显示左子树内容

DLRTree(treeNode->right);//显示右子树内容

}

}

/中序遍历算法/

voidLDRTree(CBTTypetreeNode)

{

if(treeNode)

{



LDRTree(treeNode->left);//显示左子树内容

ShowNodeData(treeNode);//显示结点内容

DLRTree(treeNode->right);//显示右子树内容

}

}

/后序遍历算法/

voidLRDTree(CBTTypetreeNode)

{

if(treeNode)

{

LRDTree(treeNode->left);//显示左子树内容

DLRTree(treeNode->right);//显示右子树内容

ShowNodeData(treeNode);//显示结点内容

}

}

/主函数部分/

intmain()

{

CBTTyperoot=NULL;//root为指向二叉树根结点的指针

charmenusel;

//设置根结点

root=InitTree();

//添加结点

do

{

cout<<"请选择菜单添加二叉树的结点:"<
cout<<"0.退出;1.添加二叉树的结点。"<
cin>>menusel;

switch(menusel)

{

case''1'':

AddTreeNode(root);

break;

case''0'':

break;

default:

cout<<"添加结点error"<
break;

}

}while(menusel!=''0'');

//输出树的深度

cout<<"depth:"<
//输出结点内容

do

{

cout<<"请选择菜单遍历二叉树,输入0表示退出:"<
cout<<"1.按层遍历"<
cout<<"2.先序遍历DLR"<
cout<<"3.中序遍历LDR"<
cout<<"4.后序遍历LRD"<
cin>>menusel;

switch(menusel)

{

case''0'':break;

case''1'':

cout<<"按层遍历的结果:"<
LevelTree(root);

cout<
break;

case''2'':

cout<<"先序遍历的结果:"<
DLRTree(root);

cout<
break;

case''3'':

cout<<"中序遍历的结果:"<
LDRTree(root);

cout<
break;

case''4'':

cout<<"后序遍历的结果:"<
LRDTree(root);

cout<
break;

default:

cout<<"遍历方式选择出错!"<
break;

}

}while(menusel!=''0'');

//清空二叉树

ClearTree(root);

return0;

}





















献花(0)
+1
(本文系白狐一梦首藏)