纸上学来终觉浅,绝知此事要躬行。——  陆游「冬夜读书示子聿」

# 二叉树

二叉树是最常用的树型数据结构,用来表示分支关系和层次关系。二叉树是由根元素、左子树和右子树组成。

满二叉树:特殊的二叉树,树中所有分支结点都有左右子树,叶子结点都在最后一层。

完全二叉树:不要求所有分支结点都有左右子树,但是要求所有已存在的结点位置与满二叉树对应,叶子结点只能出现最后一层和倒数第二层。

# 二叉树存储结构

完全二叉树和满二叉树可以直接使用顺序存储和数组存储,对二叉树结点进行编号,存放到数组对应的下标位置。这里主要介绍链式存储结构——二叉链表和三叉链表。

二叉链表采用左右孩子指针指向二叉树左右子树,三叉链表增加一个指向双亲结点的指针。

二叉链表表示:

typedef struct tree_node {

    char data;

    struct tree_node *left_child, *right_child;

}tree_node, *binary_tree;

三叉链表表示:

typedef struct tree_node {

    char data;

    struct tree_node *left_child, *right_child;

    struct tree_node *parent;

}tree_node, *binary_tree;

# 七种遍历算法

二叉树存储结构比较简单,但是需要掌握创建二叉树的方法、以及七种遍历算法。

- 先序遍历(递归实现、非递归实现)

- 中序遍历(递归实现、非递归实现)

- 后序遍历(递归实现、非递归实现)

- 层次遍历

例如对于二叉树:

        A

       /  \

      B   H

     / \

   C   D

       / \

     E    F

       \

        G

先序遍历结果:ABCDEGFH

中序遍历结果:CBEGDFAH

后序遍历结果:CGEFDBHA

层次遍历结果:ABHCDEFG

# 代码运行结果

请输入二叉树先序序列,0表示空格:ABC00DE0G00F00H00

先序遍历-递归实现:ABCDEGFH

中序遍历-递归实现:CBEGDFAH

后序遍历-递归实现:CGEFDBHA

层次遍历-队列实现:ABHCDEFG

先序遍历-非递归实现:ABCDEGFH

中序遍历-非递归实现:CBEGDFAH

后序遍历-非递归实现:CGEFDBHA

# 代码实现

建立上述二叉树,使用二叉链表实现上述七种遍历算法。首先需要根据读入的数据建立二叉树。

使用二叉树先序序列作为输入数据,其中空格表示空树,这里使用0表示空格。因此,对于上述二叉树的先序序列可以如下表示:

ABC00DE0G00F00H00。

备注:为简单起见,未作任何异常检测和处理。

/* ==========================================  名称   :C语言实现常用数据结构   功能   :二叉树   环境   :Windows 10 + Dev-C++编译    作者   :一只会C的猫   公众号 :C语言大全(coderpointer)  时间   :2020.8.15 ==========================================*/#include #include // 定义二叉树最大结点个数 #define MAX_TREE_SIZE 1000// 二叉树二叉链表表示typedef struct tree_node {  char data;  struct tree_node *left_child, *right_child;}tree_node, *binary_tree; // 根据先序序列创建二叉树void pre_create_binary_tree(binary_tree *t){  char c;  scanf("%c", &c);  if(c == '0')    *t = NULL;  else if(c != '\n')  {    *t = (tree_node *)malloc(sizeof(tree_node));    (*t)->data = c;    pre_create_binary_tree(&((*t)->left_child));    pre_create_binary_tree(&((*t)->right_child));  }  } // 先序遍历-递归实现 void pre_order_traverse(binary_tree t){  if(t != NULL)  {    printf("%c", t->data);    pre_order_traverse(t->left_child);    pre_order_traverse(t->right_child);  }}// 中序遍历-递归实现 void in_order_traverse(binary_tree t){  if(t != NULL)  {    in_order_traverse(t->left_child);    printf("%c", t->data);    in_order_traverse(t->right_child);  }}// 后序遍历-递归实现 void post_order_traverse(binary_tree t){  if(t != NULL)  {    post_order_traverse(t->left_child);    post_order_traverse(t->right_child);    printf("%c", t->data);  }}// 三种遍历非递归实现// 需要使用栈作为辅助空间// 先序遍历-非递归实现// 根结点进栈,当栈不空时,出栈访问,再先右节点先入栈,后左孩子结点入栈void pre_order(binary_tree t){  if(t == NULL)    return ;  // 使用数组实现栈  binary_tree stack[MAX_TREE_SIZE];  binary_tree p;  int top = -1;  // 根结点入栈  stack[++top] = t;  // 当栈不空  while(top > -1)  {    // 出栈访问结点    p = stack[top--];    printf("%c", p->data);        // 右孩子先入后出     if(p->right_child != NULL)      stack[++top] = p->right_child;      // 左孩子入栈    if(p->left_child != NULL)      stack[++top] = p->left_child;     }} // 中序遍历-非递归实现// 先扫描根结点所有左孩子结点,然后出栈访问,再扫描右孩子结点。 void in_order(binary_tree t){  if(t == NULL)    return ;  binary_tree stack[MAX_TREE_SIZE];  binary_tree p;  int top = -1;    p = t;  while(p != NULL || top > -1)  {    while(p != NULL)    {      // p的左孩子入栈      stack[++top] = p;      p = p->left_child;    }        if(top > -1)    {      p = stack[top--];      printf("%c", p->data);      p = p->right_child;    }  }   }  // 后序遍历-非递归实现 // 先扫描根结点所有左孩子结点,再扫描所有右孩子结点,// 左右孩子均访问过,访问当前结点。void post_order(binary_tree t){  if(t == NULL)    return ;    binary_tree stack[MAX_TREE_SIZE];  binary_tree p;  int top = -1;  int is_visited;  do  {    while(t != NULL)    {      stack[++top] = t;      t = t->left_child;    }        p = NULL;    is_visited = 1;    while(top != -1 && is_visited)    {      t = stack[top];      // 当右节点为空或者被访问过       if(t->right_child == p)      {        printf("%c", t->data);        top--;        p = t;      }else      {        t = t->right_child;        is_visited = 0;      }    }      }while(top != -1);   } // 层次遍历// 需要使用队列作为辅助空间 void level_order_traverse(binary_tree t){  if(t == NULL)    return ;  // 为简化操作,这里使用数组实现队列  // 数组大小至少等于二叉树最大结点个数  binary_tree queue[MAX_TREE_SIZE];  // 定义队头和队尾  int front, rear;  front = -1;  // 队尾指向下一个可用空间   rear = 0;  queue[rear] = t;  // 当队列不空   while(rear != front)  {    // 访问队头数据     printf("%c", queue[++front]->data);        // 将队头结点指向的下一层左孩子结点入队     if(queue[front]->left_child != NULL)      queue[++rear] = queue[front]->left_child;        // 将队头结点指向的下一层左孩子结点入队     if(queue[front]->right_child != NULL)      queue[++rear] = queue[front]->right_child;  }} int main(void){  // 创建二叉树  binary_tree t = NULL;  printf("请输入二叉树先序序列,0表示空格:");   pre_create_binary_tree(&t);    printf("先序遍历-递归实现:");   pre_order_traverse(t);  printf("\n");    printf("中序遍历-递归实现:");  in_order_traverse(t);  printf("\n");    printf("后序遍历-递归实现:");  post_order_traverse(t);  printf("\n");    printf("层次遍历-队列实现:");  level_order_traverse(t);  printf("\n");    printf("先序遍历-非递归实现:");   pre_order(t);  printf("\n");    printf("中序遍历-非递归实现:");  in_order(t);  printf("\n");    printf("后序遍历-非递归实现:");  post_order(t);  printf("\n");  return 0;}

---------- End ----------