1.遍历
所谓二叉树的遍历,是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。
由二叉树的递归定义可知,遍历一棵二叉树便要决定对根结点N、左子树L和右子树R的访问顺序。按照先遍历左子树再遍历右子树的原则,常见的遍历次序有先序(NLR)、中序(LNR)和后序(LRN)三种遍历算法,其中,序指的是根节点在何时被访问。除了上述三种遍历,还有层次遍历,前三种一般使用深度优先搜索(DFS)实现,而层次遍历一般用广度优先搜索(BFS)实现。
2.先序遍历
二叉树的递归定义中的递归边界是二叉树是一棵空树,即在递归访问子树时,如果碰到子树为空,那么就说明到达了边界。
先序遍历的操作过程:
如果二叉树为空,什么也不做,否则
(1)访问根节点
(2)先序遍历左子树
(3)先序遍历右子树
先序遍历递归的代码如下:
struct node{
int data; //数据域
node* lchild; //左指针域
node* rchild; //右指针域
};
void preorder(node* root){
if(root == NULL) return;
visit(root->data ); //访问根节点
preorder(root->lchild ); //递归访问左子树
preorder(root->rchild ); //递归访问右子树
}
3.中序遍历
中序遍历的操作过程为:
如果二叉树为空,什么也不做,否则:
(1)中序遍历左子树
(2)访问根节点
(3)中序遍历右子树
中序遍历递归代码如下:
void inorder(node* root){
if(root == NULL) return;
inorder(root->lchild ); //递归访问左子树
visit(root->data ); //访问根节点
inorder(root->rchild ); //递归访问右子树
}
4.后序遍历
后序遍历的操作过程为:
如果二叉树为空,什么也不做,否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根节点
后序遍历递归代码如下:
void postorder(node* root){
if(root == NULL) return;
postorder(root->lchild ); //递归访问左子树
postorder(root->rchild ); //递归访问右子树
visit(root->data ); //访问根节点
}
5.层次遍历
层次遍历是指按层次的顺序从根节点向下逐层进行遍历,且对同一层的结点为从左到右遍历。层次遍历就相当于对二叉树从根节点开始的广度优先搜索,基本思路如下:
(1)将根节点root加入队列q
(2)取出队首结点,访问它
(3)如果该结点有左孩子结点,将左孩子入队
(4)如果该结点有右孩子,将右孩子入队
(5)返回(2),直到队列为空。
代码如下:
void Layerorder(node* root){
queue<node*> q; //队列里存入地址
q.push(root); //将根节点地址入队
while(!=q.empty()){
node* now = q.front(); //取出队首地址
q.pop(); //将队首地址出队
printf("%d",root->data );//访问队首元素
if(root->lchild != NULL) q.push(root->lchild);
if(root->rchild != NULL) q.push(root->rchild);
}
}
6.二叉树的静态实现
静态二叉链表是指,结点的左右指针域使用int型代替,用来表示左右子树的根节点在数组中的下标。为此需要建立一个大小为结点上限个数node型数组,所有动态生成的结点都直接使用数组中的结点,所有对指针的操作都改为对数组下标的访问。结点node的定义如下:
struct node{
int data; //数据域
int lchild;//指向左子树的指针域
int rchild; // 指向右子树的指针域
}Node[maxn]; //结点数组,maxn为结点上限个数
结点的动态生成就可以转变为如下的静态指定:
int index = 0;
int newNode(int v){
Node[index].data = v;// 数据域为v
Node[index].lchild = -1;
Node[index].rchild = -1;//以-1或maxn表示空
}
//查找,root为根节点在数组中的下标
void search(int root, int x, int newdata){
if(root == -1) return; //递归边界
if(Node[root].data = x){
Node[root].data = newdata; //找到数据域为x的结点,修改数据域
}
search (root->lchild, x, newdata);
search(root->rchild, x, newdata);
}
//插入
void insert(int &root, int x){ //记得加引用
if(root == -1) {
root = newNode(x); //给root赋以新值
return;
}
if(由二叉树的性质x应该插在左子树){
insert(Node[root].lchild, x)
}
else{
insert(Node[root].rchild);
}
return root; //返回二叉树的根节点下标
}
//建立二叉树,函数返回根节点root的下标
int Create(int data[], int n) {
int root = -1; //新建根节点
for(int i=0; i<n; i++){
insert(root, data[i]);
}
return root;//返回根节点下标
}
//先序遍历
void preorder(int root){
if(root == 1) return;
visit(root->data);
preorder(Node[root].lchild);
preorder(Node[root].rchild );
}
//中序遍历
void inorder(int root){
if(root == 1) return;
inorder(Node[root].lchild);
visit(root->data);
inorder(Node[root].rchild );
}
//后序遍历
void postorder(int root){
if(root == 1) return;
postorder(Node[root].lchild);
postorder(Node[root].rchild );
visit(root->data);
}
//层次遍历
void Layerorder(int root){
queue<int> q; //队列存放结点下标
q.push(root);
while(!q.empty()){
int now = q.front();
q.pop();
printf("%d", Node[root].data );
if(Node[root].lchild != -1) q.push(Node[root].lchild );
if(Node[root].rchild != -1) q.push(Node[root].rchild );
}
}