二叉树的创建、相关操作、递归和非递归式实现三种遍历
2018-03-03 16:40
603 查看
首先,本文默认读者已经掌握了二叉树的相关概念。本文采用二叉链表作为存储结构。
定义二叉链表的结点:
下面我们新建一个二叉树结点:
其实创建二叉树就是在已有的基础上按照某种规则不断的插入新的结点到合适的位置上(比如左子树的数据域<根节点的数据域<右子树的根节点)。我们下面先来看怎么插入结点。
读者可能对为什么函数参数中使用node*&root,因为root存放的是当前节点孩子的地址,如果为空,说明这是插入新节点的地方,那么将creatnode返回的新节点的地址赋值给root,就实现了父亲和孩子的连接。但是如果不引用,函数中的root的改变不能传递给原树中该节点的指针域。也就意味这该指针域没有被修改,因此新节点没有能连接到父亲结点。因此必须使用引用。
下面见二叉树的创建:
为了方便说明,我们假设所有的数据存储在了一个数组当中,对数组边遍历边插入结点,即可创建一个二叉树。
二叉树的查找和修改:
使用递归,其实就是从根节点出发,顺着子树一直往下查找,一直到NULL,递归结束。
二叉树的先序遍历(递归式):
先序遍历按照根节点->左子树->右子树的顺序
注意:对一个二叉树的先序遍历序列,第一个一定是该二叉树的根节点
二叉树的先序遍历(非递归式):
非递归需要栈的帮助。工作指针为设为now,每次它所指的结点不空,则对其进行访问,然后压入栈中,now往其左子树走。如果now所指结点为空,那么就从栈中弹出一个节点赋值给now,now往这个节点的右子树走。
二叉树的中序遍历(递归式):
访问顺序为左子树->根节点->右子树。
二叉树的中序遍历(非递归式):
这个类别先序遍历即可。
二叉树后序遍历(递归式):
访问顺序:左子树->右子树->根节点。
二叉树后序遍历(非递归式):
后续遍历的非递归式要麻烦一些,因为最后才访问根节点,因此需要对它的子树结点进行标记,防止重复进栈。
定义二叉链表的结点:
struct node{ int data; //数据域 node*lchild; //指向左子树根节点的指针 node*rchild; //指向右子树根节点的指针 };
下面我们新建一个二叉树结点:
node* creatnode(int x){ //创建新的结点 node*root =new node; //使用new分配结点空间 root->data =x; //对数据域进行赋值 root->lchild=root->rchild=NULL; //这一句很重要,因为是新的结点还没有对其插入子树,一定置为NULL。 return root; //返回新建结点的地址。 }
其实创建二叉树就是在已有的基础上按照某种规则不断的插入新的结点到合适的位置上(比如左子树的数据域<根节点的数据域<右子树的根节点)。我们下面先来看怎么插入结点。
void insert(node*&root,int x){ //往树中查找一个节点,因为要改变二叉树,因此要使用引用,不然新的结点连接不到父亲节点上面 if(root==NULL){ //递归边界,也是插入的位置。 root=creatnode(x); //将新结点链接上去 return; } if(x>=root->data){ //我这里使用的时查找二叉树(BST)的规则作为条件 insert(root->rchild,x); //在左子树中递归插入 } else insert(root->lchild,x); //在右子树中递归查询。 }
读者可能对为什么函数参数中使用node*&root,因为root存放的是当前节点孩子的地址,如果为空,说明这是插入新节点的地方,那么将creatnode返回的新节点的地址赋值给root,就实现了父亲和孩子的连接。但是如果不引用,函数中的root的改变不能传递给原树中该节点的指针域。也就意味这该指针域没有被修改,因此新节点没有能连接到父亲结点。因此必须使用引用。
下面见二叉树的创建:
为了方便说明,我们假设所有的数据存储在了一个数组当中,对数组边遍历边插入结点,即可创建一个二叉树。
node*creatTree(int arr[],int n){ //建立树,arr数组存放所有的数据,n表示节点的个数 node*Tree=NULL; //首先创建根节点并置空 for(int i=0;i<n;i++){ insert(Tree,arr[i]); //依次插入即可 } return Tree; //最后返回根节点的值 }
二叉树的查找和修改:
使用递归,其实就是从根节点出发,顺着子树一直往下查找,一直到NULL,递归结束。
void search(node*root,int x,int newdata){ //查找、修改操作 if(root==NULL){ //空树了,递归边界 return; } if(root->data==x){ root->data=newdata; //对数据域进行修改 } search(root->lchild,x,newdata); //递归查询左子树 search(root->rchild,x,newdata); //递归查询右子树 }
二叉树的先序遍历(递归式):
先序遍历按照根节点->左子树->右子树的顺序
void preorder1(node*root){ //先序遍历 if(root==NULL){ //递归边界 return; } printf("%d ",root->data); //访问根结点 preorder(root->lchild); //递归访问左子树 preorder(root->rchild); //递归访问右子树 }
注意:对一个二叉树的先序遍历序列,第一个一定是该二叉树的根节点
二叉树的先序遍历(非递归式):
非递归需要栈的帮助。工作指针为设为now,每次它所指的结点不空,则对其进行访问,然后压入栈中,now往其左子树走。如果now所指结点为空,那么就从栈中弹出一个节点赋值给now,now往这个节点的右子树走。
void preorder2(node*root){ stack<node*> s; node*now=root; while(now!=NULL||!s.empty()){ if(now!=NULL){ s.push(now); printf("%d ",now->data); now=now->lchild; } else{ now=s.top(); s.pop(); now=now->rchild; } } }
二叉树的中序遍历(递归式):
访问顺序为左子树->根节点->右子树。
void inorder1(node*root){ //中序遍历 if(root==NULL){ return; } inorder1(root->lchild); printf("%d ",root->data); inorder1(root->rchild); }
二叉树的中序遍历(非递归式):
这个类别先序遍历即可。
void inorder2(node*root){ stack<node*> s; node*now=root; while(now!=NULL||!s.empty()){ if(now!=NULL){ s.push(now); now=now->lchild; } else{ now=s.top(); //取得栈顶元素 printf("%d ",now->data); //访问 s.pop(); //将栈顶结点弹出 now=now->rchild; //往右子树方向遍历 } } }
二叉树后序遍历(递归式):
访问顺序:左子树->右子树->根节点。
void postorder(node*root){ //后序遍历 if(root==NULL){ return; } postorder(root->lchild); postorder(root->rchild); printf("%d ",root->data); }
二叉树后序遍历(非递归式):
后续遍历的非递归式要麻烦一些,因为最后才访问根节点,因此需要对它的子树结点进行标记,防止重复进栈。
void postorder2(node*root){ stack<node*> s; //需要使用栈进行存储 node*now,*p; //now为工作指针,p为标记指针,标记刚被访问过的结点 now=root;p=NULL; //初始化 while(now!=NULL||!s.empty()){ if(now!=NULL){ //如果不是空结点,那么进行压栈,往左走。 s.push(now); now=now->lchild; } else{ now=s.top(); //取得栈顶元素。 if(now->rchild!=NULL&&now->rchild!=p){ //如果该节点的右子树不空而且没有被访问过 now=now->rchild; //走向右子树 } else{ printf("%d ",now->data); //左右子树为空,或者都已经被访问过了,输出该节点 s.pop(); //出栈 p=now; //p标记刚被访问的结点 now=NULL; //将now置空,使其能返回父亲结点走向右子树。 } } } }
相关文章推荐
- 【python中二叉树的实现】python中二叉树的创建、三种方式递归遍历和非递归遍历
- 数据结构学习之-二叉树的三种递归遍历C++实现及相关应用
- 二叉树的递归遍历非递归遍历以及其他二叉树的相关操作实现(数据结构)
- C++实现二叉树所有操作 -- 创建递归遍历迭代遍历拷贝清空查找
- 数据结构(二叉树系列)先序创建三种遍历和求深度(递归实现)
- java实现二叉树的创建及三种递归遍历
- 不疯魔,不成活!——二叉树的创建、遍历(递归实现)等操作。
- 二叉树(一):二叉树的创建以及三种遍历方法的递归实现
- 用java实现二叉树相关操作(前序建树,前中后递归非递归遍历,层序遍历)
- 用c语言创建一颗二叉树,用递归方法实现对其进行先序、中序和后序遍历的操作。
- 二叉树相关操作(前序遍历,中序遍历,后序遍历,层次序遍历等)递归和非递归实现
- C++递归创建、非递归遍历二叉树的基本操作
- 二叉树三种遍历方式的递归和循环实现
- 二叉树的创建,插入,删除,输出,求高度,求度以及三种遍历方式实现
- 二叉树的创建与前序中序后序遍历的递归实现
- Java实现二叉树的创建和遍历操作(有更新)
- 二叉树基本操作--创建,三种遍历,叶子节点
- 二叉树的建立以及三种遍历方式的递归、非递归的实现
- 二叉树的各种操作的(递归非递归)的实现,如(递归非递归)先序后序中序层次遍历 二叉树的高度 叶子节点数,所有节点数
- 二叉树的创建、前序中序后序递归遍历与非递归遍历、层序遍历以及二叉树简单应用的C语言实现