最近发现一个不错的项目,Github上数据结构所有算法源码实现:《数据结构》-严蔚敏.吴伟民-教材源码与习题解析
1.采用二叉链表结构实现二叉树
并以递归遍历思想实现二叉树的创建、二叉树的遍历(先序、中序、后序和层次遍历)、二叉树叶子节点统计、二叉树深度统计的算法;同时,结合课件和实例代码,实现二叉树的中序非递归遍历算法。存储结构和操作接口定义如下:
/*①二叉树的二叉链表存储结构定义*/
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild; //左右孩子指针
}BiTNode, *BiTree;
/*栈的顺序存储结构定义*/
typedef BiTree SElemType;
typedef struct
{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
/*②二叉树操作接口定义*/
//1-创建二叉树
/*初始化操作, 建立一个二叉数 */
void InitTree(BiTree* T);
/*若二叉树存在, 插入值e */
void InsertTree(BiTree* T, char e);
/*判断二叉树是否为空, 空返回true, 否则false */
bool TreeEmpty(BiTree T);
//2-先序遍历二叉树(递归算法)
//先序遍历二叉树T的递归算法
void PreOrderTraverse(BiTree T);
//3-中序遍历二叉树(递归算法)
//中序遍历二叉树T的递归算法
void InOrderTraverse(BiTree T);
//4-后序遍历二叉树(递归算法)
//后序遍历二叉树T的递归算法
void PostOrderTraverse(BiTree T);
//5-中序遍历二叉树(非递归算法)
//中序遍历二叉树T的递归算法,对每个数据元素调用函数Visit,非递归算法,
//采用栈作为辅助结构,注意栈中存储的数据类型是指向树结点的指针
Status InOrderTraverse1(BiTree T, Status(*Visit)(ElemType));
//6-层次遍历二叉树
//层次遍历二叉树T的递归算法,对每个数据元素调用函数Visit,采用队列作为辅助结构
Status LevelOrderTraverse(BiTree T, Status(*Visit)(ElemType));
//7-统计树的叶子结点个数
int CountLeafs(BiTree T);
//8-统计树的层次数
int CountLevels(BiTree T);
//打印元素
Status PrintElement(BiTree T);
//构造一个空栈
Status InitStack(SqStack &S);
//进栈
Status Push(SqStack &S, SElemType e);
//退栈
Status Pop(SqStack &S, SElemType &e);
//判断栈是否为空
Status StackEmpty(SqStack S);
2.测试例子
测试二叉树为:
其叶子结点:4;深度:4
先序:ABDHEICFG
中序:HDBIEAFCG
后序:HDIEBFGCA
层次:ABCDEFGHI
验证结果(完整代码在下一节):
结果完全一致!!!!!
推荐理解二叉树遍历的视频:
三分钟无脑学会二叉树遍历手工算法_哔哩哔哩_bilibili
无脑秒解!已知先/后序遍历与中序遍历,求后/先序遍历。_哔哩哔哩_bilibili
3.完整代码(复制就能运行):
#include "stdafx.h"
#include<stdlib.h>
#include<stdio.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
typedef char ElemType;
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
/*①二叉树的二叉链表存储结构定义*/
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild; //左右孩子指针
}BiTNode, *BiTree;
/*栈的顺序存储结构定义*/
typedef BiTree SElemType;
typedef struct
{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
//1-创建二叉树
/*初始化操作, 建立一个二叉数 */
void InitTree(BiTree* T);
/*若二叉树存在, 插入值e */
void InsertTree(BiTree* T, char e);
/*判断二叉树是否为空, 空返回true, 否则false */
bool TreeEmpty(BiTree T);
//2-先序遍历二叉树(递归算法)
//先序遍历二叉树T的递归算法
void PreOrderTraverse(BiTree T);
//3-中序遍历二叉树(递归算法)
//中序遍历二叉树T的递归算法
void InOrderTraverse(BiTree T);
//4-后序遍历二叉树(递归算法)
//后序遍历二叉树T的递归算法
void PostOrderTraverse(BiTree T);
//5-中序遍历二叉树(非递归算法)
//中序遍历二叉树T的递归算法,对每个数据元素调用函数Visit,非递归算法,
//采用栈作为辅助结构,注意栈中存储的数据类型是指向树结点的指针
Status InOrderTraverse1(BiTree T, Status(*Visit)(ElemType));
//6-层次遍历二叉树
//层次遍历二叉树T的递归算法,对每个数据元素调用函数Visit,采用队列作为辅助结构
Status LevelOrderTraverse(BiTree T, Status(*Visit)(ElemType));
//7-统计树的叶子结点个数
int CountLeafs(BiTree T);
//8-统计树的层次数
int CountLevels(BiTree T);
//打印元素
Status PrintElement(BiTree T);
//构造一个空栈
Status InitStack(SqStack &S);
//进栈
Status Push(SqStack &S, SElemType e);
//退栈
Status Pop(SqStack &S, SElemType &e);
//判断栈是否为空
Status StackEmpty(SqStack S);
#pragma region 1.创建二叉树
//1-创建二叉树
/*初始化操作, 建立一个二叉数 */
void InitTree(BiTree* T)
{
*T = NULL;
}
BiTree FindElem(BiTree T, char e)
{
if (T->data == e)
return T;
if (T->data < e)
{
if (T->rchild == NULL)
return T;
return FindElem(T->rchild, e);
}
if (T->data > e)
{
if (T->lchild == NULL)
return T;
return FindElem(T->lchild, e);
}
return NULL;
}
//创建结点
BiTree CreateNode(char value)
{
BiTree new_node = (BiTNode *)calloc(1, sizeof(BiTNode));
new_node->data = value;
new_node->lchild = NULL;
new_node->rchild = NULL;
return new_node;
}
/*若二叉树不存在, 创建二叉树并把e赋给根结点,否则平衡插入值e */
void InsertTree(BiTree* T, char e)
{
BiTree o = (BiTNode *)calloc(1, sizeof(BiTNode));
o->data = e;
if (*T == NULL)
{
*T = o;
return;
}
BiTree root = FindElem(*T, e);
if (root == NULL)
return;
if (root->data < e)
{
root->rchild = o;
}
else if (root->data > e)
{
root->lchild = o;
}
else
{
printf("结点已经存在了\n", e);
free(o);
o = NULL;
return;
}
}
// 按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树,
// 构造二叉链表表示的二叉树T。
Status CreateBiTree(BiTree &T)
{
ElemType ch;
ch = getchar();
if (ch == ' ') T = NULL;
else
{
if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) exit(OVERFLOW);
T->data = ch; // 生成根结点
CreateBiTree(T->lchild); // 构造左子树
CreateBiTree(T->rchild); // 构造右子树
}
return OK;
} // CreateBiTree
//打印元素
Status PrintElement(ElemType e)
{
printf("%c ", e);
return OK;
}
#pragma endregion
#pragma region 2 先序遍历二叉树(递归算法)
//2-先序遍历二叉树(递归算法)
/* 初始条件: 二叉树T存在 */
/* 操作结果: 前序递归遍历T */
void PreOrderTraverse(BiTree T)
{
if (!T) return;
printf("%c ", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}//PreOrderTraverse
#pragma endregion
#pragma region 3 中序遍历二叉树(递归算法)
//3-中序遍历二叉树(递归算法)
/* 初始条件: 二叉树T存在 */
/* 操作结果: 中序递归遍历T */
void InOrderTraverse(BiTree T)
{
if (!T) return;
InOrderTraverse(T->lchild);
printf("%c ", T->data);
InOrderTraverse(T->rchild);
}//InOrderTraverse
#pragma endregion
#pragma region 4 后序遍历二叉树(递归算法)
//4-后序遍历二叉树(递归算法)
/* 初始条件: 二叉树T存在 */
/* 操作结果: 后序递归遍历T */
void PostOrderTraverse(BiTree T)
{
if (!T) return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c ", T->data);
}//PostOrderTraverse
#pragma endregion
#pragma region 5 中序遍历二叉树(非递归算法)
//构造一个空栈
Status InitStack(SqStack &S)
{
S.base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!S.base) {
printf("栈溢出!\n");
exit(OVERFLOW);
}
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return OK;
}
//进栈
Status Push(SqStack &S, SElemType e)
{
if (S.top - S.base >= S.stacksize)
{
S.base = (SElemType *)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!S.base)
{
printf("栈溢出!\n");
return OVERFLOW;
}
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}//若栈满,追加存储空间
*S.top++ = e;
return OK;
}
//出栈
Status Pop(SqStack &S, SElemType &e)
{
if (StackEmpty(S))
return ERROR; //判空
e = *(--S.top);
return OK;
}
//判断栈是否为空
Status StackEmpty(SqStack S)
{
if (S.top == S.base)
return TRUE;
else
return FALSE;
}
//5-中序遍历二叉树(非递归算法)
//中序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit,
//采用栈作为辅助结构,注意栈中存储的数据类型是指向树结点的指针
Status InOrderTraverse1(BiTree T, Status(*Visit)(ElemType))
{
SqStack S;
BiTree p;
p = T;
InitStack(S);
while (p || !StackEmpty(S))
{
if (p) { Push(S, p); p = p->lchild; } // 非空指针进栈,继续左进
else { // 上层指针退栈,访问其所指结点,再向右进
Pop(S, p);
if (!Visit(p->data))
return ERROR;
p = p->rchild;
}
}
return OK;
} // InOrderTraverse
#pragma endregion
#pragma region 6 层次遍历二叉树
//6-层次遍历二叉树
//层次遍历二叉树T的递归算法,对每个数据元素调用函数Visit,采用队列作为辅助结构
Status LevelOrderTraverse(BiTree T, Status(*Visit)(ElemType))
{
BiTNode *Queue[100], *p = T;
int front = 0, rear = 0;
if (p != NULL)
{
Queue[++rear] = p; /* 根结点入队 */
while (front<rear)
{
p = Queue[++front]; Visit(p->data);
if (p->lchild != NULL)
Queue[++rear] = p->lchild; /* 左结点入队 */
if (p->rchild != NULL)
Queue[++rear] = p->rchild; /* 左结点入队 */
}
return OK;
}
return ERROR;
}
#pragma endregion
#pragma region 7 统计树的叶子结点个数
//7-统计树的叶子结点个数
/*若二叉树存在, 输出其结点个数 */
int CountLeafs(BiTree root)
{
if (root == NULL)
{
return 0;
}
if (root->lchild == NULL&&root->rchild == NULL)
{
return 1;
}
return CountLeafs(root->lchild) + CountLeafs(root->rchild);
}
#pragma endregion
#pragma region 8 统计树的层次数
//8-统计树的层次数
/* 初始条件: 二叉树T存在。操作结果: 返回T的深度 */
int CountLevels(BiTree T)
{
if (T == NULL)
return 0;
int l = 0, r = 0;
if (T->lchild)
l = CountLevels(T->lchild);
if (T->rchild)
r = CountLevels(T->rchild);
return l > r ? l + 1 : r + 1;
}
#pragma endregion
void main()
{
BiTree T;
int n = 0;
/*创建二叉树 start*/
InitTree(&T);
BiTree a = CreateNode('a');
BiTree b = CreateNode('b');
BiTree c = CreateNode('c');
BiTree d = CreateNode('d');
BiTree e = CreateNode('e');
BiTree f = CreateNode('f');
BiTree g = CreateNode('g');
BiTree h = CreateNode('h');
BiTree i = CreateNode('i');
T = a;//根结点a
a->lchild = b;//a结点左子树b
a->rchild = c;//a结点右子树c
b->lchild = d;//b结点左子树d
b->rchild = e;//b结点右子树e
c->lchild = f;//c结点左子树f
c->rchild = g;//c结点右子树g
d->lchild = h;//d结点左子树h
e->lchild = i;//e结点左子树i
/*创建二叉树 end*/
n = CountLeafs(T);
printf("树的叶子结点个数为:%d", n);
printf("\n树的层次数为:%d\n", CountLevels(T));
printf("先序遍历二叉树(递归算法):");
PreOrderTraverse(T);
printf("\n中序遍历二叉树(递归算法):");
InOrderTraverse(T);
printf("\n后序遍历二叉树(递归算法):");
PostOrderTraverse(T);
printf("\n中序遍历二叉树(非递归算法):");
InOrderTraverse1(T, PrintElement);
printf("\n层次遍历二叉树(递归算法):");
LevelOrderTraverse(T, PrintElement);
printf("\n");
}