纸上学来终觉浅,绝知此事要躬行。——
陆游「冬夜读书示子聿」
# 二叉树
二叉树是最常用的树型数据结构,用来表示分支关系和层次关系。二叉树是由根元素、左子树和右子树组成。
满二叉树:特殊的二叉树,树中所有分支结点都有左右子树,叶子结点都在最后一层。
完全二叉树:不要求所有分支结点都有左右子树,但是要求所有已存在的结点位置与满二叉树对应,叶子结点只能出现最后一层和倒数第二层。
# 二叉树存储结构
完全二叉树和满二叉树可以直接使用顺序存储和数组存储,对二叉树结点进行编号,存放到数组对应的下标位置。这里主要介绍链式存储结构——二叉链表和三叉链表。
二叉链表采用左右孩子指针指向二叉树左右子树,三叉链表增加一个指向双亲结点的指针。
二叉链表表示:
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 ----------