二叉树
本文有模仿部分,侵删
文章目录
一棵二叉树T是一个有穷的结点集合。这个集合可以为空,若不为空,则它是由根结点和称为其左子树TL和右子树TR的两个不相交的二叉树组成。可见左子树和右子树还是二叉树。
特殊二叉树
二叉树的深度小于结点数N,可以证明平均深度是O(根号n)
“斜二叉树(Skewed Binary Tree)”(也称为退化二叉树);
“完美二叉树(Perfect Binary Tree)”。(也称为满二叉树)。
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1 ≤ i ≤ n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为“完全二叉树(Complete Binary Tree)”。完全二叉树适合用数组存储
如图不是完全二叉树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qIFO2G5n-1644995320070)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211020202002263.png)]
二叉树的性质
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uHSEix7d-1644995320072)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205125834500.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OkoW8GYS-1644995320073)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205125854557.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E6iHnIIG-1644995320073)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205125913247.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sU52IZGI-1644995320074)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205125932870.png)]
二叉树的链表存储
Left | Data | Right |
---|---|---|
指针 | 数据 | 指针 |
struct TreeNode{
ElementType Data;
struct TreeNode* Left;
struct TreeNode* Right;
};
typedef struct TreeNode *BinTree;
typedef struct TreeNode position;
二叉树的操作
类型名称:二叉树(BinTree)
数据对象集:一个有限的结点集合。这个集合可以为空,若不为空,则它是由根结点和其左、右二叉子树组成。
操作集:对于所有 BT, BT1, BT2 BinTree, Item ElementType,重要的操作有:
1、Boolean IsEmpty( BinTree BT ): 若BT为空返回TRUE; 否则返回FALSE;
2、void Traversal( BinTree BT ):二叉树的遍历,即按某一顺序访问二叉树中的每个结点仅一次;
3、BinTree CreatBinTree( ):创建一个二叉树。
二叉树的创建
先序创建和层序创建
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNmmjHZE-1644995320074)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211130195239804.png)]
二叉树的左右链存储结构(二叉链表)的建立
//方法1
BinTree CreateBT(datatype v, BinTree ltree , BinTree rtree )
{
BinTree root ;
root = new node ;
root →data = v ;
root →lchild = ltree ;
root →rchild = rtree ;
return root ;
}
//法二:我在这里实现的是,二叉树的前序遍历方式创建,如果要使用中序或者后序的方式建立二叉树,只需将生成结点和构造左右子树的顺序改变即可
void CreateBiTree(BiTree T)
{
char ch;
scanf("%c",&ch);
if(ch=='#')
T=NULL;
else
{
T=(BiTree)malloc(sizeof(BiTNode));
if(!T)
exit(-1);
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}//注意:此法实际行不通
//下面给出两解决法
//1
Binarytree recursion_creat(Binarytree T)
{
char ch;
scanf("%c", &ch);
fflush(stdin);//清除标准输入流的缓存
if (ch != '#')
{
T = (Binarytree)malloc(sizeof(TREE));
T->data = ch;
T->lson = NULL;
T->rson = NULL;
T->lson = recursion_creat(T->lson);
T->rson = recursion_creat(T->rson);
}
return T;
}//完整代码见最底部
//下面是老师帮改的代码,有些地方还不对,记得还得再调
//树的操作
#include <iostream>
#define max 20
using namespace std;
//树的表示
struct Treenode{
int data;
struct Treenode *lchild;
struct Treenode *rchild;
struct Treenode *father;
};
//栈
typedef struct node{
Treenode *s[max];
int top;
}Stack;
void initStack(Stack *H);
void myPush(Stack *H, Treenode *T);
Treenode* myPop(Stack *H);
void inorder_create(Treenode*BT);//前序递归建树
void inorder_travel(Treenode*BT);//前序遍历
void midorder_travel(Treenode*BT);//中序遍历,非递归
void postorder_travel(Treenode*BT);//后序遍历
void level_order(Treenode*BT);//层序遍历
int main(){
Treenode*T = new Treenode;
inorder_create(T);
inorder_travel(T);
cout << '\n';
midorder_travel(T);
cout << '\n';
postorder_travel(T);
system("pause");
return 0;
}
int arr[10] = { 1, 3, 4, 5, 61, 33, 15, 23, 34, 42 };
int x = 10;
//先序遍历建表
void inorder_create(Treenode *T){
int m;
cin >> m;
if (m == -1){
if (T->father == nullptr)
{
return;
}
else{
if (T->father->lchild == T)
{
T->father->lchild = nullptr;
delete T;
T = nullptr;
}
else{
T->father->rchild = nullptr;
delete T;
T = nullptr;
}
}
}
else{
T->data = m;
T->lchild = new Treenode;
T->lchild->father = T;
T->rchild = new Treenode;
T->rchild->father = T;
inorder_create(T->lchild);
inorder_create(T->rchild);
}
}
//先序遍历
void inorder_travel(Treenode *BT){
if (BT == nullptr)
return;
cout << BT->data << '\t';
inorder_travel(BT->lchild);
inorder_travel(BT->rchild);
}
void midorder_travel(Treenode *BT){
Treenode*T = BT;
Stack *H = new Stack;
initStack(H);
while (T){
myPush(H, T);
T = T->lchild;
}
if (H->top != -1){
T = myPop(H);
cout << T->data << '\t';
T = T->rchild;
}
}
void postorder_travel(Treenode *BT){
if (!BT)
return;
postorder_travel(BT->lchild);
postorder_travel(BT->rchild);
cout << BT->data << '\t';
}
void initStack(Stack *H){
if (!H)
return;
for (int i = 0; i < max; i++){
H->s[i] = new Treenode;
}
H->top = -1;
}
void myPush(Stack *H, Treenode *T){
if (H->top == max - 1){
cout << "栈满" << endl;
return;
}
H->s[++H->top] = T;
}
Treenode* myPop(Stack *H){
if (H->top == -1)
return nullptr;
return H->s[H->top--];
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZhsbukxN-1644995320074)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205130413520.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wgpN3Emv-1644995320075)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211205130439346.png)]
遍历(递归)
//先序遍历
void PreOrderTraversal( BinTree BT )
{
if( BT ) {
printf(“%d”, BT->Data);//放中间变成中序,放最后变成后序
PreOrderTraversal( BT->Left );
PreOrderTraversal( BT->Right );
}
}//要能判断遍历的顺序,三种序列走的路径相同,只是不同节点在不同序列中被print出来有先后
//中序遍历
void InOrderTraversal( BinTree BT ) {
if( BT ) {
InOrderTraversal( BT->Left );
printf(“%d”, BT->Data);
InOrderTraversal( BT->Right );
} }
//后序遍历
void PostOrderTraversal( BinTree BT ) {
if( BT ) {
PostOrderTraversal( BT->Left );
PostOrderTraversal( BT->Right);
printf(“%d”, BT->Data);
} }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cWdAD3p-1644995320075)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211020203518183.png)]
二叉树非递归遍历(使用堆栈)
中序遍历
遇到一个结点,就把它压栈并访问它,然后去遍历它的左子树;
当左子树遍历结束后,从栈顶弹出这个结点;
然后按其右指针再去中序遍历该结点的右子树。
void InOrderTraversal( BinTree BT )
{ BinTree T=BT;
Stack S = CreatStack( MaxSize ); /*创建并初始化堆栈S*/
while( T || !IsEmpty(S) ){
while(T){ /*一直向左并将沿途结点压入堆栈*/
Push(S,T);
T = T->Left;
}
if(!IsEmpty(S)){
T = Pop(S); /*结点弹出堆栈*/
printf(“%5d”, T->Data); /*(访问)打印结点,放到前面合适位置变成先序*/
T = T->Right; /*转向右子树*/
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FCHzuF4T-1644995320076)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211129233657165.png)]
后序遍历的非递归算法
int* postorderTraversal(BinTree root, int* returnSize)
{
if( root == NULL ) return NULL;
/**自定义结果数组并初始化**/
int* result = (int*)malloc(1000*sizeof(int));
int len = 0;
/**定义栈并初始化**/
Sq_stack* stk_result = (Sq_stack*)malloc(sizeof(Sq_stack));
initStack(stk_result);
Sq_stack* temp_stk = (Sq_stack*)malloc(sizeof(Sq_stack));
initStack(temp_stk);
while( root || !isEmptyStack(temp_stk) )
{
/**将当前结点同时入临时栈和结果栈【根】,并遍历右子树----【右】**/
while( root )
{
Push(temp_stk,root);
Push(stk_result,root);
root = root->right;
}
/**当右子树遍历结束后,弹出临时栈栈顶结点,并遍历其左子树----【左】,继续while**/
if( !isEmptyStack(temp_stk) )
{
root = Pop(temp_stk);
root = root->left;
}
}
/**当所有结点都访问完,即最后访问的树节点为空且临时栈也为空时,
主算法结束,依次pop出结果栈结点**/
BinTree e = (BinTree)malloc(sizeof(Position));
while( !isEmptyStack(stk_result) )
{
e = Pop(stk_result);
result[len++] = e->data;
}
free(e);
*returnSize = len;
return result;
}
层序遍历(队列实现)
void LevelOrderTraversal ( BinTree BT )
{ Queue Q; BinTree T;
if ( !BT ) return; /* 若是空树则直接返回 */
Q = CreatQueue( MaxSize ); /*创建并初始化队列Q*/
AddQ( Q, BT );//根节点入队
while ( !IsEmptyQ( Q ) ) {
T = DeleteQ( Q );//从开头抛出一个元素
printf(“%d\n”, T->Data); /*访问取出队列的结点*/
if ( T->Left ) AddQ( Q, T->Left );
if ( T->Right ) AddQ( Q, T->Right );
}
}
//最终实现了一层一层访问
遍历二叉树的应用
例一:输出二叉树中的叶子结点
void PreOrderPrintLeaves( BinTree BT )
{
if( BT ) {//左右节点都为空
if ( !BT-Left && !BT->Right )
printf(“%d ”, BT->Data );
PreOrderPrintLeaves ( BT->Left );
PreOrderPrintLeaves ( BT->Right );
}
}
例二:求二叉树的高度
//求左右子树的最大高度
int PostOrderGetHeight( BinTree BT )
{ int HL, HR, MaxH;
if( BT ) {
HL = PostOrderGetHeight(BT->Left); /*求左子树的深度*/
HR = PostOrderGetHeight(BT->Right); /*求右子树的深度*/
MaxH = HL > HR? HL : HR; /*取左右子树较大的深度*/
return ( MaxH + 1 ); /*返回树的深度*/
}
else return 0; /* 空树深度为0 */
}
例三:二元运算表达式树及其遍历
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F9cTdoMG-1644995320077)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211130194734973.png)]
例四:由两种遍历来确定一棵树(要唯一确定必须的有中序遍历结果)
没有中序的困扰:
先序遍历序列:A B
后序遍历序列:B A 确定不了B是A的左孩子还是右孩子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chrQcQ5w-1644995320077)(C:\Users\Π\AppData\Roaming\Typora\typora-user-images\image-20211130195022624.png)]
代码
//树的操作,带父节点
#include <iostream>
#define max 20
using namespace std;
//树的表示
struct Treenode{
int data;
struct Treenode *lchild;
struct Treenode *rchild;
struct Treenode *father;
};
//栈
typedef struct node{
Treenode *s[max];
int top;
}Stack;
void initStack(Stack *H);
void myPush(Stack *H, Treenode *T);
Treenode* myPop(Stack *H);
void inorder_create(Treenode*BT);//前序递归建树
void inorder_travel(Treenode*BT);//前序遍历
void midorder_travel(Treenode*BT);//中序遍历,非递归
void postorder_travel(Treenode*BT);//后序遍历
void level_order(Treenode*BT);//层序遍历
int main(){
Treenode*T = new Treenode;
inorder_create(T);
inorder_travel(T);
cout << '\n';
midorder_travel(T);
cout << '\n';
postorder_travel(T);
system("pause");
return 0;
}
int arr[10] = { 1, 3, 4, 5, 61, 33, 15, 23, 34, 42 };
int x = 10;
//先序遍历建表
void inorder_create(Treenode *T){
int m;
cin >> m;
if (m == -1){
if (T->father == nullptr)
{
return;
}
else{
if (T->father->lchild == T)
{
T->father->lchild = nullptr;
delete T;
T = nullptr;
}
else{
T->father->rchild = nullptr;
delete T;
T = nullptr;
}
}
}
else{
T->data = m;
T->lchild = new Treenode;
T->lchild->father = T;
T->rchild = new Treenode;
T->rchild->father = T;
inorder_create(T->lchild);
inorder_create(T->rchild);
}
}
//先序遍历
void inorder_travel(Treenode *BT){
if (BT == nullptr)
return;
cout << BT->data << '\t';
inorder_travel(BT->lchild);
inorder_travel(BT->rchild);
}
void midorder_travel(Treenode *BT){
Treenode*T = BT;
Stack *H = new Stack;
initStack(H);
while (T){
myPush(H, T);
T = T->lchild;
}
if (H->top != -1){
T = myPop(H);
cout << T->data << '\t';
T = T->rchild;
}
}
void postorder_travel(Treenode *BT){
if (!BT)
return;
postorder_travel(BT->lchild);
postorder_travel(BT->rchild);
cout << BT->data << '\t';
}
void initStack(Stack *H){
if (!H)
return;
for (int i = 0; i < max; i++){
H->s[i] = new Treenode;
}
H->top = -1;
}
void myPush(Stack *H, Treenode *T){
if (H->top == max - 1){
cout << "栈满" << endl;
return;
}
H->s[++H->top] = T;
}
Treenode* myPop(Stack *H){
if (H->top == -1)
return nullptr;
return H->s[H->top--];
}
完整c语言代码(转载)
#include<stdio.h>
#include<stdlib.h>
typedef struct Binary_Tree
{
char data; //结点的数据域
struct Binary_Tree *lson;
struct Binary_Tree *rson;
}TREE, *Binarytree;
//各函数声名
Binarytree recursion_creat(Binarytree T); //运用递归方法创建二叉树
void preorder_traversal(Binarytree T); //前序遍历
void inorder_traversal(Binarytree T); //非递归实现中序遍历
void postorder_traversal(Binarytree T); //非递归实现后序遍历
void exchange_subtree(Binarytree T); //交换左右子树
int height_calculation(Binarytree T); //统计高度
void swap(Binarytree Tree1, Binarytree Tree2);
int main()
{
Binarytree T1, T2;
int height, flag = 1;
printf("请依次输入节点的值,以'#'号结束\n\n");
T2 = recursion_creat(T1);
printf("\n\n创建成功!\n\n");
while (flag = 1)
{
printf("-----------------------------------");
printf("\n");
printf("--------1 输出前序遍历结果----------\n\n");
printf("--------2 输出中序遍历结果----------\n\n");
printf("--------3 输出后序遍历结果----------\n\n");
printf("--------4 交换左右子树--------------\n\n");
printf("--------5 统计二叉树的高度----------\n\n");
printf("--------6 退出----------------------\n\n");
printf("\n\n请输入您的选择:");
int m;
scanf("%d", &m);
switch (m)
{
case 1:
printf("\n\n前序遍历结果为:\n\n");
preorder_traversal(T2);
printf("\n\n");
break;
case 2:
printf("\n\n中序遍历结果为:\n\n");
inorder_traversal(T2);
printf("\n\n");
break;
case 3:
printf("\n\n后序遍历结果为:\n\n");
postorder_traversal(T2);
printf("\n\n");
break;
case 4:
exchange_subtree(T2);
printf("交换成功!");
printf("\n\n");
break;
case 5:
printf("\n\n此二叉树的高度为:\n\n");
height = height_calculation(T2);
printf("%d", height);
printf("\n\n");
break;
case 6:exit(0);
default:printf("输入错误!"); break;
}
}
return 0;
}
Binarytree recursion_creat(Binarytree T)
{
char ch;
scanf("%c", &ch);
fflush(stdin);//清除标准输入流的缓存
if (ch != '#')
{
T = (Binarytree)malloc(sizeof(TREE));
T->data = ch;
T->lson = NULL;
T->rson = NULL;
T->lson = recursion_creat(T->lson);
T->rson = recursion_creat(T->rson);
}
return T;
}
void preorder_traversal(Binarytree T)
{
if (T != NULL)
{
printf("%c", T->data);
//依次遍历左子树和右子树
preorder_traversal(T->lson);
preorder_traversal(T->rson);
}
}
void inorder_traversal(Binarytree T)
{
int index = 0; //栈顶
Binarytree data[100];
do
{
while (T != NULL)
{
index++;
data[index] = T;
T = T->lson;
}
if (index != 0)
{
T = data[index];
index--;
printf("%c", T->data);
T = T->rson;
}
} while (T != NULL || index != 0);
}
void postorder_traversal(Binarytree T)
{
Binarytree S[100], P;
int flag, top = 0;
if (T != NULL)
{
do{
while (T != NULL)
{
S[top++] = T; //入栈
T = T->lson;//遍历左子树
}
P = NULL;//
flag = 1; //已访问
while (top && flag)
{
T = S[top - 1]; //退栈
if (T->rson == P) //
{
printf("%c", T->data);//访问
top--;
P = T;//
}
else
{
T = T->rson;
flag = 0;
}
}
} while (top);
printf("\n\n");
}
}
void exchange_subtree(Binarytree T)
{
if (!T))
{
return;//退出
}
else
{
swap(T->lson, T->rson);
exchange_subtree(T->lson);
exchange_subtree(T->rson);
}
}
void swap(Binarytree Tree1, Binarytree Tree2)
{
Binarytree temp;
temp = Tree1;
Tree1 = Tree2;
Tree2 = temp;
}
int height_calculation(Binarytree T)
{
int height_lson;
int height_rson;
int max;
if (T == NULL)
{
return 0;
}
height_lson = height_calculation(T->lson);
height_rson = height_calculation(T->rson);
max = height_lson > height_rson ? height_lson : height_rson;
return max + 1;
}