1.二叉树性质
二叉树性质:
性质1:在二叉树第i层上至多有2的i-1次方个结点
性质2:深度为k的二叉树至多有2的k次方-1个结点
证明:深度为K,有K层,等比数列求和
a1(1-q^n)/(1-q)
1(1-2^k)/(1-2) = 2^k-1
性质3:对于任何一颗二叉树,若度为2的结点数有n2个,则叶子数(n0)必定为n2+1,即n0=n2+1
证明:设一共结点数为n,度为1的结点数位n1,叶子数为n0,它的度为0
n=n1+n2+n0
2*n2+1*n1+n0=n-1(计算每个节点的子节点总数,因为没算根节点)
推出:
2*n2+n1=n1+n2+n0-1
n0=n2+1;
性质4:具有n个结点的完全二叉树的深度必为 不大于log以2为底n为对数的最大整数+1
性质5:对完全二叉树,若从上至下,从左至右编号,编号为i的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1时为根)
2.二叉树的遍历与实现
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char data; //数据域
struct TreeNode* lchild; //左子树
struct TreeNode* rchild; //右子树
}TreeNode;
//创建二叉树
void CreateTree(TreeNode** T, char* data, int* index);
//递归方法
//先序遍历
void PreOrder(TreeNode* T);
//中序遍历
void inOrder(TreeNode* T);
//后序遍历
void postOrder(TreeNode* T);
#include"tree.h"
void CreateTree(TreeNode** T, char* data,int* index)
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#') //此时为空节点 人为假设输入#为空
{
*T = NULL;
}
else //此时不为空
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index);
//创建右子树
CreateTree(&((*T)->rchild), data, index);
}
}
//先序遍历——递归
void PreOrder(TreeNode* T)
{
if (T == NULL)
{
return;
}
else
{
printf("%c ", T->data);
// 递归
//先序遍历:根 左 右
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序遍历——递归
void inOrder(TreeNode* T)
{
if (T == NULL)
{
return;
}
else
{
// 递归
//中序遍历:左 根 右
inOrder(T->lchild);
printf("%c ", T->data);
inOrder(T->rchild);
}
}
//后序遍历——递归
void postOrder(TreeNode* T)
{
if (T == NULL)
{
return;
}
else
{
// 递归
//后序遍历:左 右 根
postOrder(T->lchild);
postOrder(T->rchild);
printf("%c ", T->data);
}
}
#include"tree.h"
int main()
{
int index = 0;
char data[] = { 'A','B','#','#','C','#','#' };
TreeNode* T;
CreateTree(&T,data,&index);
PreOrder(T);
printf("\n");
inOrder(T);
printf("\n");
postOrder(T);
printf("\n");
return 0;
}
3.二叉树的层次遍历实现
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef struct TreeNode
{
char data; //数据域
struct TreeNode* lchild; //左子树
struct TreeNode* rchild; //右子树
}TreeNode;
//层次遍历需要用到队列
typedef struct QueueNode
{
TreeNode* data;//将树的节点放入队列
struct QueueNode* prev;
struct QueueNode* next;
}QueueNode;
//创建二叉树
void CreateTree(TreeNode** T, char* data, int* index);
//创建队列
QueueNode* InitQueue();
void QueuePush(QueueNode* pq, TreeNode* x);//队尾插入
bool QueueEmpty(QueueNode* pq);//判断是否为空
QueueNode* QueuePop(QueueNode* pq);//队头删除
void levelTraverse(QueueNode* pq, TreeNode* T);//二叉树的层次遍历
void FreeTreeAndQueue(QueueNode* pq, TreeNode** T);//队列头节点的内存释放
#include"treelevel.h"
void CreateTree(TreeNode** T, char* data, int* index)
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#') //此时为空节点 人为假设输入#为空
{
*T = NULL;
}
else //此时不为空
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index);
//创建右子树
CreateTree(&((*T)->rchild), data, index);
}
}
//带头双向链表
QueueNode* InitQueue()
{
QueueNode* q = (QueueNode*)malloc(sizeof(QueueNode));
TreeNode* T = (TreeNode*)malloc(sizeof(TreeNode));
if (q == NULL)
{
printf("Queue create fail\n");
exit(1);
}
if (T == NULL)
{
printf("TreeNode head create fail\n");
exit(1);
}
T->data = ' ';
T->lchild = NULL;
T->rchild = NULL;
q->data = T;
q->next = q;
q->prev = q;
return q;
}
//队尾插入
void QueuePush(QueueNode* pq, TreeNode* x)
{
assert(pq);
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
newnode->data = x;
QueueNode* tail = pq->prev;
tail->next = newnode;
newnode->prev = tail;
pq->prev = newnode;
newnode->next = pq;
}
//判断是否为空
bool QueueEmpty(QueueNode* pq)
{
return (pq->next == pq);
}
//队头删除
QueueNode* QueuePop(QueueNode* pq)
{
if (QueueEmpty(pq))
{
return NULL;
}
else
{
QueueNode* next = (QueueNode*)malloc(sizeof(QueueNode));
next = pq->next;
if (next->next!= NULL)
{
pq->next = next->next;
next->next->prev = pq;
next->prev = next;
next->next = next;
}
return next;
}
}
//例如
// A
// B C
// D E F G
// 循环前队列:A
// 第一次循环
//出队:A
//列队:B C
// 第二次循环
//出队:A B
//列队:C D E
// 第三次循环
//出队:A B C
//列队:D E F G
// 第四次循环
//出队:A B C D
//列队:E F G
// 第五次循环
//出队:A B C D E
//列队:F G
// 第六次循环
//出队:A B C D E F
//列队G
// 第七次循环
//出队:A B C D E F G
//列队:
//出循环
void levelTraverse(QueueNode* pq, TreeNode* T)
{
//根节点进队
QueuePush(pq, T);
//不为空时出队
while (!QueueEmpty(pq))
{
QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));
node = QueuePop(pq);
/*free(QueuePop(pq));
QueuePop(pq) = NULL;*/
//node->data指向树节点
printf("%c ", node->data->data);//打印树节点
if (node->data->lchild!=NULL)//左节点不为空,进队
{
QueuePush(pq, node->data->lchild);
}
if (node->data->rchild!=NULL)//右节点不为空,进队
{
QueuePush(pq, node->data->rchild);
}
//释放空间
//每个打印的树节点内存都释放 树节点还剩根节点未释放
//存储它们的队列节点内存也都释放 队列还剩头节点未释放
free(node->data);
node->data = NULL;
free(node);
node = NULL;
}
}
//队列头节点的内存释放
void FreeTreeAndQueue(QueueNode* pq, TreeNode** T)
{
free(pq->data);
pq->data = NULL;
free(pq);
pq = NULL;
}
4.二叉树前序、中序、后序遍历的非递归实现
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
//循环方法
//前序、中序遍历思想:
//1.入栈根节点
//2。循环,直到左孩子为空
//3.出栈,入栈右孩子
typedef struct TreeNode
{
char data;
struct TreeNode* lchild;
struct TreeNode* rchild;
int flag;//后序遍历时记录 右节点是否被访问过
}TreeNode;
//带头链表栈
typedef struct StackNode
{
TreeNode* data;
struct StackNode* next;
}StackNode;
void CreateTree(TreeNode** T, char* data, int* index);//二叉树的实现
StackNode* InitStack();//初始化栈
void StackPush(StackNode* S, TreeNode* data);//头插 入栈
StackNode* StackPop(StackNode* S);//头删 出栈
bool isEmpty(StackNode* S);//判断是否为空
void PreOrder(TreeNode* T); //先序遍历——循环实现
void inOrder(TreeNode* T); //中序遍历——循环实现
void postOrder(TreeNode* T);//后序遍历——循环实现 方法一
void postOrder2(TreeNode* T);//后序遍历——循环实现 方法二
#include"tree.h"
void CreateTree(TreeNode** T, char* data, int* index)
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#') //此时为空节点 人为假设输入#为空
{
*T = NULL;
}
else //此时不为空
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
(*T)->flag = 0;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index);
//创建右子树
CreateTree(&((*T)->rchild), data, index);
}
}
//创建栈
StackNode* InitStack()
{
StackNode* S = (StackNode*)malloc(sizeof(StackNode));
S->data = NULL;
S->next = NULL;
return S;
}
//头插
void StackPush(StackNode* S, TreeNode* data)
{
StackNode* newnode = (StackNode*)malloc(sizeof(StackNode));
newnode->data = data;
newnode->next = S->next;
S->next = newnode;
}
//判断是否为空
bool isEmpty(StackNode* S)
{
return (S->next == NULL);
}
//头删 出栈
StackNode* StackPop(StackNode* S)
{
if (isEmpty(S))
{
return NULL;
}
else
{
StackNode* cur = S->next;
S->next = cur->next;
return cur;
}
}
//前序、中序遍历思想:
//1.入栈根节点
//2。循环,直到左孩子为空
//3.出栈,入栈右孩子
//先序遍历——循环实现
// A
// B C
// D E F G
//第一次循环
//输出 A
//栈: A
//第二次循环
//输出 B
//栈:A B
//第三次循环
//输出 D
//栈:A B D
// node=NULL
//出栈:D,同时node置为D
//node=E
//麻烦?效率?
void PreOrder(TreeNode* T)
{
TreeNode* node = T;
StackNode* S = InitStack();
while (node || !isEmpty(S))
{
if (node)
{
//先序遍历 根 左 右
printf("%c ", node->data);
//入栈
StackPush(S, node);
node = node->lchild;
}
else//上一个节点的左孩子为空,出栈,入栈右孩子
{
//此时node为空,返回上一层
//StackPop(S)是栈链表节点,它存储的数据是树节点
node = StackPop(S)->data;
node = node->rchild;//得到上一层的右节点
}
}
}
//中序遍历——循环实现 左 中 右
void inOrder(TreeNode* T)
{
TreeNode* node = T;
StackNode* S = InitStack();
while (node || !isEmpty(S))
{
if (node)
{
//入栈
StackPush(S, node);
node = node->lchild;
}
else
{
node = StackPop(S)->data;
printf("%c ", node->data);
node = node->rchild;
}
}
}
//后序遍历——循环实现 左 右 根
//思想:
//1,从根节点开始,寻找最左边的节点,并依此入栈
//2.出栈前,判断栈顶元素是否有右子树以及右子树是否被访问过,如果有则将右子树入栈
//方法一
//获得栈顶,并且不真正出栈
StackNode* getTop(StackNode* S)
{
if (isEmpty(S))
{
return NULL;
}
else
{
StackNode* cur = S->next;
return cur;
}
}
void postOrder(TreeNode* T)
{
TreeNode* node = T;
StackNode* S = InitStack();
while (node || !isEmpty(S))
{
if (node)
{
StackPush(S, node);//进栈
node = node->lchild;
}
else
{
TreeNode* top = getTop(S)->data;
if (top->rchild && top->rchild->flag == 0)
{
top = top->rchild;
StackPush(S, top);
node = top->lchild;
}
else
{
top = StackPop(S)->data;
printf("%c ", top->data);
top->flag = 1;
}
}
}
}
//方法二
void postOrder2(TreeNode* T)
{
TreeNode* node = T;
TreeNode* prevAccess = NULL;
StackNode* S = InitStack();
while (node || !isEmpty(S))
{
if (node)
{
StackPush(S, node);
node = node->lchild;
}
else
{
node = StackPop(S)->data;
if (node->rchild == NULL || node->rchild == prevAccess)
{
printf("%c ", node->data);
prevAccess = node;
node = NULL;
}
else
{
StackPush(S, node);
node = node->rchild;
}
}
}
}
#include"tree.h"
int main()
{
int index = 0;
char data[] = { 'A','B','D','#','#','E','#','#','C','F','#','#','G','#','#' };
TreeNode* T;
CreateTree(&T, data, &index);
PreOrder(T);
printf("\n");
inOrder(T);
printf("\n");
postOrder(T);
printf("\n");
postOrder2(T);
printf("\n");
return 0;
}
5.求二叉树叶子节点个数
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char ch;
struct TreeNode* lchild;
struct TreeNode* rchind;
}TreeNode;
void calculateLeafNum(TreeNode* root,int* num)
{
//递归的结束条件
if(root==NULL)
{
return;
}
if(root->lchild==NULL&&root->rchind==NULL)
{
(*num)++;
}
calculateLeafNum(root->lchild,num);
calculateLeafNum(root->rchind,num);
}
void test01()
{
TreeNode nodeA={'A',NULL,NULL};
TreeNode nodeB={'B',NULL,NULL};
TreeNode nodeC={'C',NULL,NULL};
TreeNode nodeD={'D',NULL,NULL};
TreeNode nodeE={'E',NULL,NULL};
TreeNode nodeF={'F',NULL,NULL};
TreeNode nodeG={'G',NULL,NULL};
TreeNode nodeH={'H',NULL,NULL};
//建立关系
nodeA.lchild=&nodeB;
nodeA.rchind=&nodeF;
nodeB.rchind=&nodeC;
nodeC.lchild=&nodeD;
nodeC.rchind=&nodeE;
nodeF.rchind=&nodeG;
nodeG.lchild=&nodeH;
//求树中叶子节点的个数
int num=0;
calculateLeafNum(&nodeA,&num);
printf("叶子节点的数量为:%d\n",num);
}
int main()
{
test01();
return 0;
}
6.求二叉树的高度(深度)
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char ch;
struct TreeNode* lchild;
struct TreeNode* rchind;
}TreeNode;
int getTreeHeight(TreeNode* root)
{
if(root==NULL)
{
return 0;
}
//求出左子树高度
int LeftHeight=getTreeHeight(root->lchild);
int RightHeight=getTreeHeight(root->rchind);
int height=LeftHeight>RightHeight?LeftHeight+1:RightHeight+1;
return height;
}
void test01()
{
TreeNode nodeA={'A',NULL,NULL};
TreeNode nodeB={'B',NULL,NULL};
TreeNode nodeC={'C',NULL,NULL};
TreeNode nodeD={'D',NULL,NULL};
TreeNode nodeE={'E',NULL,NULL};
TreeNode nodeF={'F',NULL,NULL};
TreeNode nodeG={'G',NULL,NULL};
TreeNode nodeH={'H',NULL,NULL};
//建立关系
nodeA.lchild=&nodeB;
nodeA.rchind=&nodeF;
nodeB.rchind=&nodeC;
nodeC.lchild=&nodeD;
nodeC.rchind=&nodeE;
nodeF.rchind=&nodeG;
nodeG.lchild=&nodeH;
//求树的高度
int height=getTreeHeight(&nodeA);
printf("树的高度:%d\n",height);
}
int main()
{
test01();
return 0;
}
7.二叉树的拷贝及释放
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char ch;
struct TreeNode* lchild;
struct TreeNode* rchind;
}TreeNode;
TreeNode* copyTree(TreeNode* root)
{
if(root==NULL)
{
return NULL;
}
//先拷贝左子树
TreeNode* lchild=copyTree(root->lchild);
//再拷贝右子树
TreeNode* rchild=copyTree(root->rchind);
//再创建新的节点
TreeNode* newroot=(TreeNode*)malloc(sizeof(TreeNode));
newroot->ch=root->ch;
newroot->lchild=lchild;
newroot->rchind=rchild;
return newroot;
}
void showTree(TreeNode* root)
{
if(root==NULL)
{
return;
}
printf("%c ",root->ch);
showTree(root->lchild);
showTree(root->rchind);
}
void DestroyTree(TreeNode* root)
{
if(root==NULL)
{
return;
}
DestroyTree(root->lchild);
DestroyTree(root->rchind);
printf("%c 被释放\n",root->ch);
free(root);
root=NULL;
}
void test01()
{
TreeNode nodeA={'A',NULL,NULL};
TreeNode nodeB={'B',NULL,NULL};
TreeNode nodeC={'C',NULL,NULL};
TreeNode nodeD={'D',NULL,NULL};
TreeNode nodeE={'E',NULL,NULL};
TreeNode nodeF={'F',NULL,NULL};
TreeNode nodeG={'G',NULL,NULL};
TreeNode nodeH={'H',NULL,NULL};
//建立关系
nodeA.lchild=&nodeB;
nodeA.rchind=&nodeF;
nodeB.rchind=&nodeC;
nodeC.lchild=&nodeD;
nodeC.rchind=&nodeE;
nodeF.rchind=&nodeG;
nodeG.lchild=&nodeH;
TreeNode* newroot=copyTree(&nodeA);
showTree(newroot);
printf("\n");
DestroyTree(newroot);
}
int main()
{
test01();
return 0;
}
8.一维数组树
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<math.h>
#define MAX_SIZE 1024 //一维数组能够存放的最大结点数
//树的顺序存储结构——一般用于完全二叉树,这样可以避免内存浪费
//将二叉树按层序存放进一维数组中
typedef int TElemType;//树节点的结构类型,目前定义为整形
typedef int SeqTree[MAX_SIZE];//定义顺序数
typedef struct
{
int level;//结点所在二叉树中的第几层
int order;//在这层的第几个,标为序号
}Position;
//放在头文件会引起,重定义的错误
TElemType Nil = 0;//设定整形以零为空
//初始化空二叉树
//因为tree是固定数组,不会改变,所以不需要传指针
void InitSeqTree(SeqTree tree)
{
//将字符数组中每个元素都设置为空字符
for (int i = 0; i < MAX_SIZE; i++)
{
tree[i] = Nil;
}
}
//创建完全二叉树
void CreateSeqTree(SeqTree tree)
{
int i = 0;
//随便创建一个二叉树
while (i < 10)
{
tree[i] = i + 1;
//出现不为空的,无双亲结点
//设根结点的序号为1,后面某二叉树结点序号为K
//K/2为,此结点的双亲序号
//此时,i从0开始,那么他的序号按上述算法该为i+1
//它的双亲序号应为(i+1)/2
//在数组中的存储下标应该再减一
if (i != 0 && tree[(i + 1) / 2 - 1] == Nil && tree[i] != Nil)
{
printf("出现无双亲的非根结点:%d\n", tree[i]);
return;
}
i++;
}
while (i < MAX_SIZE)
{
//将空赋给后面的值
tree[i] = Nil;
i++;
}
}
//判断树是否为空
bool IsTreeEmpty(SeqTree tree)
{
return tree[0] == Nil;//若根结点为空,则树为空
}
//计算二叉树的深度
int SeqTreeDepth(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
printf("二叉树为空\n");
return 0;
}
else
{
int i = 0;
for (i = MAX_SIZE - 1; i >= 0; i--)
{
if (tree[i] != Nil)//找到二叉树的最后一个结点
{
break;
}
}
int j = 0;
//结点数为下标加1
//i+1<=2^j-1
while ((i + 1) >= (powl(2, j) - 1))
{
j++;
}
return j;
}
}
//返回二叉树的根
int SeqTreeRoot(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
return 0;
}
else
{
return tree[0];
}
}
//返回本层序号的树结点的值
TElemType SeqTreeValue(SeqTree tree, Position e)
{
if (IsTreeEmpty(tree))
{
return 0;
}
return tree[(int)powl(2, e.level - 1) - 1 + e.order - 1];
}
//给本层序号的树结点赋新值value
void Assign(SeqTree tree, Position e, TElemType value)
{
if (IsTreeEmpty(tree))
{
return;
}
int i = (int)powl(2, e.level - 1) - 1 + e.order - 1;
if (value != Nil && tree[(i + 1) / 2 - 1 ] == Nil)
{
printf("给双亲为空的树节点赋非空值\n");
return;
}
else if (value == Nil && tree[2 * (i + 1) - 1] != Nil || tree[2 * (i + 1) - 1 + 1] != Nil)
{
printf("给双亲赋空值但叶子非空\n");
return;
}
tree[i] = value;
}
// 若e是T的非根结点, 则返回它的双亲, 否则返回"空"
TElemType Parent(SeqTree tree, TElemType e)
{
if (IsTreeEmpty(tree))
{
return Nil;
}
for (int i = 1; i < MAX_SIZE; i++)
{
if (tree[i] == e)
{
return tree[(i + 1) / 2 - 1];
}
}
return Nil;
}
//返回e的左孩子。若e无左孩子,则返回"空"
TElemType LeftChild(SeqTree tree, TElemType e)
{
if (IsTreeEmpty(tree))
{
return Nil;
}
for (int i = 0; i < MAX_SIZE; i++)
{
if (tree[i] == e)
{
return tree[2 * (i + 1) - 1];
}
}
return Nil;
}
//返回e的右孩子。若e无右孩子,则返回"空"
TElemType RightChild(SeqTree tree, TElemType e)
{
if (IsTreeEmpty(tree))
{
return Nil;
}
for (int i = 0; i < MAX_SIZE; i++)
{
if (tree[i] == e)
{
return tree[2 * (i + 1) + 1 - 1];
}
}
return Nil;
}
//返回e的左兄弟。若e是T的左孩子或无左兄弟,则返回"空"
TElemType LeftSibling(SeqTree tree, TElemType e)
{
if (IsTreeEmpty(tree))
{
return Nil;
}
for (int i = 0; i < MAX_SIZE; i++)
{
if (tree[i] == e && i % 2 == 0)
{
return tree[i - 1];
}
}
return Nil;
}
//返回e的右兄弟。若e是T的右孩子或无右兄弟,则返回"空"
TElemType RightSibling(SeqTree tree, TElemType e)
{
if (IsTreeEmpty(tree))
{
return Nil;
}
for (int i = 0; i < MAX_SIZE; i++)
{
if (tree[i] == e && i % 2 == 1)//e是左孩子
{
return tree[i + 1];
}
}
return Nil;
}
//先序遍历调用
void PreTraverse(SeqTree tree, int e)
{
printf("%d ", tree[e]);
if (tree[2 * (e + 1) - 1] != Nil)//左子树不为空
{
PreTraverse(tree, 2 * (e + 1) - 1);
}
if (tree[2 * (e + 1) + 1 - 1] != Nil)//右子树不为空
{
PreTraverse(tree, 2 * (e + 1) + 1 - 1);
}
}
//先序遍历
void PreOrderTraverse(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
return;
}
PreTraverse(tree, 0);
printf("\n");
}
//中序遍历调用
void InTraverse(SeqTree tree, int e)
{
if (tree[2 * (e + 1) - 1] != Nil)//左子树不为空
{
InTraverse(tree, 2 * (e + 1) - 1);
}
printf("%d ", tree[e]);
if (tree[2 * (e + 1) + 1 - 1] != Nil)//右子树不为空
{
InTraverse(tree, 2 * (e + 1) + 1 - 1);
}
}
//中序遍历
void InOrderTraverse(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
return;
}
InTraverse(tree, 0);
printf("\n");
}
//后序遍历调用
void PostTraverse(SeqTree tree, int e)
{
if (tree[2 * (e + 1) - 1] != Nil)//左子树不为空
{
PostTraverse(tree, 2 * (e + 1) - 1);
}
if (tree[2 * (e + 1) + 1 - 1] != Nil)//右子树不为空
{
PostTraverse(tree, 2 * (e + 1) + 1 - 1);
}
printf("%d ", tree[e]);
}
//后序遍历
void PostOrderTraverse(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
return;
}
PostTraverse(tree, 0);
printf("\n");
}
//层序遍历
void LevelOrderTraverse(SeqTree tree)
{
if (IsTreeEmpty(tree))
{
return;
}
int i = MAX_SIZE - 1;
while (tree[i] == Nil)//找到最后一个非空结点的下标
{
i--;
}
for (int j = 0; j <= i; j++)//因为按层存进数组,所以遍历数组,就是按层序遍历
{
if (tree[j] != Nil)//只打印非空
{
printf("%d ", tree[j]);
}
}
printf("\n");
}
//逐层、按本层序号输出二叉树
void LevelPrint(SeqTree tree)
{
Position p;
for (int j = 1; j <= SeqTreeDepth(tree); j++)//j是第几层
{
printf("第%d层:\n", j);
for (int k = 1; k <= powl(2, j - 1); k++)
{
p.level = j;
p.order = k;
TElemType e = SeqTreeValue(tree, p);//返回本层序号的树结点的值
if (e != Nil)
{
printf("第%d个:%d", k, e);
}
}
}
}
//清空树
void ClearSeqTree(SeqTree tree)
{
//将字符数组中每个元素都设置为空字符
for (int i = 0; i < MAX_SIZE; i++)
{
tree[i] = Nil;
}
}
int main()
{
SeqTree tree;
InitSeqTree(tree);
CreateSeqTree(tree);
printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n", IsTreeEmpty(tree), SeqTreeDepth(tree));
if (SeqTreeRoot(tree))
{
printf("二叉树的根为:%d\n", SeqTreeRoot(tree));
}
else
{
printf("树空,无根\n");
}
printf("层序遍历二叉树:\n");
LevelOrderTraverse(tree);
printf("前序遍历二叉树:\n");
PreOrderTraverse(tree);
printf("中序遍历二叉树:\n");
InOrderTraverse(tree);
printf("后序遍历二叉树:\n");
PostOrderTraverse(tree);
printf("修改结点的层号3本层序号2。");
Position p;
p.level = 3;
p.order = 2;
TElemType e = SeqTreeValue(tree, p);//返回3层 2序号的结点值
printf("待修改结点的原值为%d请输入新值:50 ", e);
e = 50;
Assign(tree, p, e);//修改3层2序号结点的值为50
printf("前序遍历二叉树:\n");
PreOrderTraverse(tree);
printf("结点%d的双亲为%d,", e, Parent(tree, e));
printf("左右孩子分别为%d,%d,", LeftChild(tree, e), RightChild(tree, e));
printf("左右兄弟分别为%d,%d\n", LeftSibling(tree, e), RightSibling(tree, e));
ClearSeqTree(tree);
printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n", IsTreeEmpty(tree), SeqTreeDepth(tree));
if (SeqTreeRoot(tree))
{
printf("二叉树的根为:%d\n", SeqTreeRoot(tree));
}
else
{
printf("树空,无根\n");
}
return 0;
}
9.线索二叉树
(1)中序线索二叉树
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char data;
struct TreeNode* lchild;
struct TreeNode* rchild;
int ltag;//==0 时,指向子树
int rtag;//==0 时,指向子树
}TreeNode;
void CreateTree(TreeNode** T, char* data, int* index);//二叉树的创建
void inThreadTree(TreeNode* T, TreeNode** prev);//中序线索二叉树
TreeNode* getFirst(TreeNode* T);// 找到最左子树,即中序遍历的第一个
TreeNode* getNext(TreeNode* node);//找到后继
//二叉树的创建
void CreateTree(TreeNode** T, char* data, int* index)//先序创建
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
*T = NULL;
}
else
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
(*T)->ltag = 0;
(*T)->rtag = 0;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index);
//创建右子树
CreateTree(&((*T)->rchild), data, index);
}
}
//中序线索二叉树
void inThreadTree(TreeNode* T, TreeNode** prev)//prev代表当前结点的前驱
{
if (T)
{
inThreadTree(T->lchild, prev);
//do something
if (T->lchild == NULL)//当前结点的左孩子为空
{
T->ltag = 1;//标志为1
T->lchild = *prev;//左孩子指向当前结点的前驱
}
if (*prev != NULL && (*prev)->rchild == NULL)//当前结点的前驱不为空,并且前驱的右孩子为空
{
(*prev)->rtag = 1; //前驱的标志为1
(*prev)->rchild = T; //递归中T代表的是当前结点,前驱的后继指向当前结点
}
*prev = T;//每次处理完,前驱变为当前结点
inThreadTree(T->rchild, prev);//前面没有改变本结点的右孩子指向,所以可以直接传入
}
}
// 找到最左子树,即中序遍历的第一个
TreeNode* getFirst(TreeNode* T)
{
while (T->ltag == 0)
{
T = T->lchild;
}
return T;
}
//找到后继
TreeNode* getNext(TreeNode* node)
{
if (node->rtag == 1)
{
return node->rchild;
}
else
{
return getFirst(node->rchild);
}
}
int main()
{
int index = 0;
char data[] = { 'A','B','D','#','#','E','#','#','C','#','#'};
TreeNode* T;
CreateTree(&T, data, &index);
TreeNode* prev = NULL;
inThreadTree(T, &prev);
prev->rtag = 1;
prev->rchild = NULL;
for (TreeNode* node = getFirst(T); node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
printf("\n");
return 0;
}
(2)先序线索二叉树
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char data;
struct TreeNode* lchild;
struct TreeNode* rchild;
int ltag;//==0 时,指向子树
int rtag;//==0 时,指向子树
}TreeNode;
void CreateTree(TreeNode** T, char* data, int* index);//先序二叉树的创建
void preThreadTree(TreeNode* T, TreeNode** prev);//先序线索二叉树
TreeNode* getNext(TreeNode* node);//找到后继
//二叉树的创建
void CreateTree(TreeNode** T, char* data, int* index)//先序创建
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
*T = NULL;
}
else
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
(*T)->ltag = 0;
(*T)->rtag = 0;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index);
//创建右子树
CreateTree(&((*T)->rchild), data, index);
}
}
//先序线索二叉树
void preThreadTree(TreeNode* T, TreeNode** prev)//prev代表当前结点的前驱
{
if (T)
{
//do something
if (T->lchild == NULL)//当前结点的左孩子为空
{
T->ltag = 1;//标志为1
T->lchild = *prev;//左孩子指向当前结点的前驱
}
if (*prev != NULL && (*prev)->rchild == NULL)//当前结点的前驱不为空,并且前驱的右孩子为空
{
(*prev)->rtag = 1; //前驱的标志为1
(*prev)->rchild = T; //递归中T代表的是当前结点,前驱的后继指向当前结点
}
*prev = T;//每次处理完,前驱变为当前结点
//因为如果左右孩子为空,左右孩子将会指向前驱和后继
//此时递归,就将前驱和后继传进,而原本则是想让左右子树结点传入递归
//所以需要判断是否发生改变
if (T->ltag == 0)
{
preThreadTree(T->lchild, prev);
}
if (T->rtag == 0)
{
preThreadTree(T->rchild, prev);
}
}
}
//不需要找到第一个结点的函数,因为先序遍历,第一个结点就为根节点
//找到后继
TreeNode* getNext(TreeNode* node)
{
if (node->rtag == 1)//无右孩子,右孩子指向后继
{
return node->rchild;
}
else//有右孩子,则此节点为某一子树的根,先序遍历的顺序:根、左、右
{
if (node->ltag == 0)//如果有左孩子
{
return node->lchild;//此节点之后应为其左孩子
}
else//有右孩子,无左孩子,则根之后为右孩子
{
return node->rchild;
}
}
}
int main()
{
int index = 0;
char data[] = { 'A','B','#','#','C','#','#' };
TreeNode* T;
CreateTree(&T, data, &index);
TreeNode* prev = NULL;
preThreadTree(T, &prev);
prev->rtag = 1;
prev->rchild = NULL;
for (TreeNode* node = T; node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
printf("\n");
return 0;
}
(3)后序线索二叉树
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
char data;
struct TreeNode* lchild;
struct TreeNode* rchild;
struct TreeNode* parent;
int ltag;//==0 时,指向子树
int rtag;//==0 时,指向子树
}TreeNode;
void CreateTree(TreeNode** T, char* data, int* index, TreeNode* parent);//先序二叉树的创建
void postThreadTree(TreeNode* T, TreeNode** prev);//后序线索二叉树
TreeNode* getFirst(TreeNode* T);// 找到最左子树,即中序遍历的第一个
TreeNode* getNext(TreeNode* node);//找到后继
//二叉树的创建
void CreateTree(TreeNode** T, char* data, int* index,TreeNode* parent)//先序创建
{
//创建二叉树的逻辑
//主函数写字符数组,直接传进来,写进二叉树
//index为序号 在主函数定义,为全局变量
//向后遍历时加加,index需要一直改变,所以指针传递
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
*T = NULL;
}
else
{
*T = (TreeNode*)malloc(sizeof(TreeNode)); //开辟一个节点的空间
//赋值
(*T)->data = ch;
(*T)->ltag = 0;
(*T)->rtag = 0;
(*T)->parent = parent;
//递归思想 左子树和右子树都是树
//创建左子树
CreateTree(&((*T)->lchild), data, index,*T);
//创建右子树
CreateTree(&((*T)->rchild), data, index,*T);
}
}
//后序线索二叉树
void postThreadTree(TreeNode* T, TreeNode** prev)//prev代表当前结点的前驱
{
if (T)
{
postThreadTree(T->lchild, prev);
postThreadTree(T->rchild, prev);//前面没有改变本结点的右孩子指向,所以可以直接传入
//do something
if (T->lchild == NULL)//当前结点的左孩子为空
{
T->ltag = 1;//标志为1
T->lchild = *prev;//左孩子指向当前结点的前驱
}
if (*prev != NULL && (*prev)->rchild == NULL)//当前结点的前驱不为空,并且前驱的右孩子为空
{
(*prev)->rtag = 1; //前驱的标志为1
(*prev)->rchild = T; //递归中T代表的是当前结点,前驱的后继指向当前结点
}
*prev = T;//每次处理完,前驱变为当前结点
}
}
// 后序遍历的第一个
//1.找到最左边的结点
//2.判断这个结点,是否有右子树
// 如果有,则继续寻找以右子树为根的最左边结点
// 如果没有,那么第一个结点为就是最左边的
TreeNode* getFirst(TreeNode* T)
{
while (T->ltag == 0)
{
T = T->lchild;
}
if (T->rtag == 0)
{
return getFirst(T->rchild);
}
else
{
return T;
}
}
//找到后继
// 左,右,根
//是根节点。next=NULL
//是左孩子 判断父亲右子树是否为空,为空next=parent;不为空next=getFirst(parent->rchild)
//是右孩子 next=parent
TreeNode* getNext(TreeNode* node)
{
if (node->rtag == 1)
{
return node->rchild;
}
else
{ //如果是根节点
if (node->parent == NULL)
{
return NULL;
}
//如果是右孩子
else if (node->parent->rchild == node)
{
return node->parent;
}
else//如果是左孩子
{
if (node->parent->rtag == 1)//父亲右子树为空next=parent
{
return node->parent;
}
else//父亲右子树不为空next=getFirst(parent->rchild)
{
return getFirst(node->parent->rchild);
}
}
}
}
int main()
{
int index = 0;
char data[] = { 'A','B','D','#','#','E','#','#','C','#','#' };
TreeNode* T;
CreateTree(&T, data, &index,NULL);
TreeNode* prev = NULL;
postThreadTree(T, &prev);
/*prev->rtag = 1;
prev->rchild = NULL;*/ //因为后序遍历的尾是根节点,所以不能改变
for (TreeNode* node = getFirst(T); node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
printf("\n");
return 0;
}
10.创建二叉查找树(二叉排序树)
(1)特点:
特点1:每个结点的值均大于其左子树上任意节点的值
特点2:每个结点的值均小于其右子树上任意节点的值
(2)代码实现
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
int data;
struct TreeNode* lchild;
struct TreeNode* rchild;
}TreeNode;
TreeNode* bstSearch(TreeNode* T, int key);//二叉查找树的查找
void bstInsert(TreeNode** T, int data);//二叉查找树的插入
void bstDelete(TreeNode** T, int data);//二叉查找树的删除
void bstDestroy(TreeNode* T);//二叉查找树的释放
void preOrder(TreeNode* T);//先序遍历
//二叉查找树的查找
TreeNode* bstSearch(TreeNode* T, int key)
{
if (T)
{
if (T->data == key)
{
return T;
}
else if (T->data > key)
{
return bstSearch(T->lchild, key);
}
else //T->data<key
{
return bstSearch(T->rchild, key);
}
}
else
{
return NULL;
}
}
//二叉查找树的插入
void bstInsert(TreeNode** T, int data)
{
if (*T == NULL)
{
*T = (TreeNode*)malloc(sizeof(TreeNode));
(*T)->data = data;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
}
else if ((*T)->data == data)
{
return;
}
else if (data < (*T)->data)
{
bstInsert(&((*T)->lchild), data);
}
else
{
bstInsert(&((*T)->rchild), data);
}
}
//二叉查找树的删除
void bstDelete(TreeNode** T, int data)
{
}
//先序遍历
void preOrder(TreeNode* T)
{
if (T == NULL)
{
return;
}
else
{
printf("%d ", T->data);
preOrder(T->lchild);
preOrder(T->rchild);
}
}
//二叉查找树的释放
void bstDestroy(TreeNode* T)
{
if (T)
{
TreeNode* L = T->lchild;
TreeNode* R = T->rchild;
free(T);
bstDestroy(L);
bstDestroy(R);
}
else
{
return;
}
}
int main()
{
TreeNode* T = NULL;
int nums[6] = { 8,6,10,9,11,23 };
for (int i = 0; i < 6; i++)
{
bstInsert(&T, nums[i]);
}
preOrder(T);
printf("\n");
bstDestroy(T);
return 0;
}
11.平衡二叉树
1.什么是平衡二叉树(AVL)?
平衡二叉树是一棵合理的二叉排序树。
2.怎么保证合理?
平衡二叉树的左右子树高度差不超过1
3.如何构建一个平衡二叉树
①本质上跟构建二叉排序树一致
②在构建二叉排序树的过程中,如果发现树不符合高度差为1,需要进行调整。
LL RR RL LR 如果遇到多棵树不平衡,选择最小树
4.如何判断调整类型:
①找到失衡树的根节点 root
②找到导致树失衡的结点 node
Node在root的哪一侧
③判断node在root孩子的哪一侧



RL型:取最后一个结点,作为父节点,将它原先的父亲作为自己的右孩子,将父亲的父亲作为自己的左孩子,如果自己有左孩子或右孩子的话,自己原先得左孩子,连接到父亲的父亲右孩子上,自己原先的右孩子连接到父亲的左孩子上
代码实现
#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
int data;
int height;
struct TreeNode* lchild;
struct TreeNode* rchild;
}TreeNode;
int getHeight(TreeNode* node);//得到树的高度,为了使代码更清晰
int Max(int a, int b);//取最大值
//调整函数
void llRotation(TreeNode* node, TreeNode** root);//LL型
void rrRotation(TreeNode* node, TreeNode** root);//RR型
void avlInsert(TreeNode** T, int data);//向平衡二叉树中插入元素
void preOrder(TreeNode* T);//前序遍历
//得到树的高度,为了使代码更清晰
int getHeight(TreeNode* node)
{
return node ? node->height : 0;
}
int Max(int a, int b)
{
return a > b ? a : b;
}
//调整函数
//LL型
void llRotation(TreeNode* node, TreeNode** root)
{
TreeNode* temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
//位置移动,其树的高度发生改变
node->height = Max(getHeight(node->lchild), getHeight(node->rchild)) + 1;
temp->height = Max(getHeight(temp->lchild), getHeight(temp->rchild)) + 1;
*root = temp;//改变根节点
}
//RR型
void rrRotation(TreeNode* node, TreeNode** root)
{
TreeNode* temp = node->rchild;//node是temp的父亲
node->rchild = temp->lchild;//如果temp有左孩子,那么temp的父亲(即node)的右孩子指向temp的左孩子
//temp的右孩子不用处理,还在原处
temp->lchild = node;//孩子的左孩子指向父亲
//位置移动,其树的高度发生改变
node->height = Max(getHeight(node->lchild), getHeight(node->rchild)) + 1;
temp->height = Max(getHeight(temp->lchild), getHeight(temp->rchild)) + 1;
*root = temp;//改变根节点
}
//向平衡二叉树中插入元素
void avlInsert(TreeNode** T, int data)
{
if (*T == NULL)
{
*T = (TreeNode*)malloc(sizeof(TreeNode));
(*T)->data = data;
(*T)->height = 0;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
}
else if (data == (*T)->data)
{
return;
}
else if (data < (*T)->data)
{
avlInsert(&((*T)->lchild), data);
//拿到当前结点左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
//判断高度差
if (lHeight - rHeight == 2)
{
if (data < (*T)->lchild->data)//LL调整
{
llRotation(*T, T);
}
else//LR调整=先RR(root->lchild)再LL(root)
{
rrRotation((*T)->lchild, &((*T)->lchild));
llRotation(*T, T);
}
}
}
else
{
avlInsert(&((*T)->rchild), data);
//拿到当前结点左右子树的高度
int lHeight = getHeight((*T)->lchild);
int rHeight = getHeight((*T)->rchild);
//判断高度差
if (rHeight - lHeight == 2)
{
if (data > (*T)->rchild->data)//RR调整
{
rrRotation(*T, T);
}
else//RL调整=先LL(root->rchild)再RR(root)
{
llRotation((*T)->rchild, &((*T)->rchild));
rrRotation(T, *T);
}
}
}
(*T)->height = Max(getHeight((*T)->lchild), getHeight((*T)->rchild)) + 1;
}
//前序遍历
void preOrder(TreeNode* T)
{
if (T)
{
printf("%d ", T->data);
preOrder(T->lchild);
preOrder(T->rchild);
}
else
{
return;
}
}
int main()
{
TreeNode* T = NULL;
int nums[5] = { 8,7,9,5,6 };
for (int i = 0; i < 5; i++)
{
avlInsert(&T, nums[i]);
}
preOrder(T);
printf("\n");
return 0;
}
12.哈夫曼树
- 权值: 根
树的结点赋值,这个点称为权值。 1 2
- 带权路径长度:每个叶子节点的权值乘以根节点到此结点的边个数
- 什么是哈夫曼树?保证所有叶子节点的带权路径长度 和最小
- 如何通过权值 结点列表 生成哈夫曼树?
- 从节点列表中选出 第一小和第二小的结点,并组成一棵树,父亲结点的权值=两节点的权值之和
- 将生成新树再次放入结点列表中,重复第一步,直到列表中只剩一个结点
- 哈夫曼编码
左边线为0,右边线为1
- 哈夫曼树的特点
- 没有度为1的结点
- 哈夫曼树的任意非叶子结点的左右子树交换之后,仍是哈夫曼树
- N个叶子节点的哈夫曼树共有2n-1个节点
- 对于同一种权值,存在不同构的两棵哈夫曼树
- 代码实现
#include<stdio.h> #include<stdlib.h> typedef struct TreeNode { int weight;//权值 int parent; int lchild; int rchild; }TreeNode; typedef struct HFTree { TreeNode* data; int length; }HFTree; HFTree* InitTree(int* weight, int length);//初始化 int* selectMin(HFTree* T);//选择权值最小的 void CreateHFTree(HFTree* T);//创建 void preOrder(HFTree* T, int index);//层序遍历 //初始化 HFTree* InitTree(int* weight,int length)//weight权值列表 { HFTree* T = (HFTree*)malloc(sizeof(HFTree)); T->data = (TreeNode*)malloc(sizeof(TreeNode) * (2 * length - 1)); T->length = length; for (int i = 0; i < length; i++) { T->data[i].weight = weight[i]; T->data[i].parent = 0; T->data[i].lchild = -1; T->data[i].rchild = -1; } return T; } //选择权值最小的两个 int* selectMin(HFTree* T) { int min = 10000; int secondMin = 10000; int minIndex = 0; int secondIndex = 0; for (int i = 0; i < T->length; i++) { if (T->data[i].parent == 0) { if (T->data[i].weight < min) { min = T->data[i].weight; minIndex = i; } } } for (int i = 0; i < T->length; i++) { if (T->data[i].parent == 0 && i != minIndex) { if (T->data[i].weight < secondMin) { secondMin = T->data[i].weight; secondIndex = i; } } } int* res = (int*)malloc(sizeof(int) * 2); res[0] = minIndex; res[1] = secondIndex; return res; } //创建 void CreateHFTree(HFTree* T) { int* res; int min; int secondMin; int length = T->length * 2 - 1; int length1 = T->length; for (int i = length1; i < length; i++) { res = selectMin(T); min = res[0]; secondMin = res[1]; T->data[i].weight = T->data[min].weight + T->data[secondMin].weight;//父亲的权值 T->data[i].parent = 0; T->data[i].lchild = min; T->data[i].rchild = secondMin; T->data[min].parent = i; T->data[secondMin].parent = i; T->length++; } } //层序遍历 void preOrder(HFTree* T, int index) { if (index != -1)//=-1树为空 { printf("%d ", T->data[index].weight); preOrder(T, T->data[index].lchild); preOrder(T, T->data[index].rchild); } /*else { return; }*/ } int main() { int weight[4] = { 1,2,3,4 }; HFTree* T = InitTree(weight, 4); //int* res = selectMin(T); //printf("res[0]=%d", res[0]); CreateHFTree(T); preOrder(T, T->length - 1);//T->length 为根节点下标 printf("\n"); return 0; }13.翻转二叉树部分代码
#include<stdio.h> TreeNode invertTree(TreeNode root) { if(root==NULL) { return NULL; } invertTree(root.lchild); invertTree(root.rchild); TreeNode temp=root.lchild; root.lchild=root.rchild; root.rchild=temp; return root; }14.判断是否为对称二叉树部分代码
#include<stdio.h> bool deepCheck(TreeNode left,TreeNode right) { //递归的终止条件是两个结点都为空 //或者两个结点一个为空 //或者两个结点不相等 if(left==NULL&right==NULL) { return true; } if(left==NULL||right==NULL) { return false; } if(left.data!=right.data) { return false; } //再递归比较 左节点的左孩子 和 右节点的右孩子 //以及比较 左结点的右孩子 和 右结点的左孩子 return deepCheck(left.lchild,right.rchild)&&deepCheck(left.rchild,right.lchild); }
本文深入探讨了二叉树的基本概念及其多种应用,包括二叉树的性质、遍历方法、层次遍历、非递归遍历等核心内容,并介绍了二叉查找树、平衡二叉树、哈夫曼树等高级主题。
434

被折叠的 条评论
为什么被折叠?



