学习目标:
数据结构学习笔记
树(上)
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
、、
树(上)
1.树与树的表示
什么是树
树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可以划分为m(m>0)个互不相交的有限集T1、T2 、…、Tm,每个集Ti(1≤i≤m)均为树,且称为树T的子树(SubTree)。
特别地,不含任何结点(即n=0)的树,称为空树。
如下是一颗树:
树使得分层次在管理上具有更高的效率
数据管理的基本操作之一:查找
查找(Searching)
查找:根据某个给定关键字K,从集合R中找出关键字与K相同的记录。
静态查找:
/* 结构代码*/
typedef struct
{
ELementType Element[MaxSize];
int Length;
}StaticTable;
方法一:顺序查找
/*顺序查找,算法复杂度O(n)*/
int SequentialSearch (StaticTable *Tbl, ELementType K)
{
/*在表Tbl[1]~Tbl[n]中查找关键字为K的数据元素*/
int i;
Tbl->Element[0] = K; /*建立哨兵*/
for(i = Tbl->Length; Tbl->Element[i] != K;i--);
return i;
哨兵的作用:
- 在边界设值即a[0];(a[0]=K)
- 循环查找若碰到这个值可退出循环,或到了边界也可退出循环;a[i]!=K;
方法二:二分查找法
/*二分查找法,效率为O(logN)*/
int BinarySearch (StaticTable *Tbl,ELementType K)
{
/* 在表Tbl中查找关键字为K的数据元素;*/
int left,right,mid,NoFound= -1;
left = 1; /*初始化左边界*/
right = Tbl->Length; /*初始化右边界*/
while(left<=right)
{
mid = (left+right)/2; /*计算中间元素坐标*/
if(K < Tbl->Element[mid])
right = mid-1; /*调整右边界*/
else if(K > Tbl->Element[mid]); /*调整左边界*/
else return mid; /*查找成功,返回数据元素的下标*/
}
return NotFound; /*查找不成功,返回-1*/
}
2.二叉树
结构定义:
typedef struct TreeNode *BinTree;
struct TreeNode{
ELementType Data;
BinTree Left;
BinTree Right;
};
二叉树的遍历
先序遍历:
- 访问根节点;
- 先序遍历其左子树
- 先序遍历其右子树
void PerpederTeaversal(BinTree BT)
{
if(BT){
printf("%d",BT->Data);
PerpederTeaversal(BT->Left);
PerpederTeaversal(BT->Right);
}
}
中序遍历:
1.中序遍历其左子树
2. 访问根节点;
3. 中序遍历其右子树
void InOderTeaversal(BinTree BT)
{
if(BT){
InOderTeaversa(BT->Left);
printf("%d",BT->Data);
InOderTeaversa(BT->Right);
}
}
后序遍历:
void PostOrderTeaversal(BinTree BT)
{
if(BT){
PostOrderTeaversal(BT->Left);
PostOrderTeaversal(BT->Right);
printf("%d",BT->Data);
}
}
先序 ,后序和中序遍历过程:遍历过程中经过结点的路线一样,只是访问各节点的时机不同。
二叉树的非递归遍历
即使用堆栈
中序遍历非递归遍历算法
- 遇到一个结点,就把它压栈,并去遍历它的左子树;
- 当左子树遍历结束后,从栈顶弹出这个结点并访问它;
- 然后按其右指针再去中序遍历该结点的右子树。
/*二叉树的中序遍历非递归遍历算法*/
void InOrderTeabersal(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; /*转向右子树*/
}
}
}
层次遍历
二叉树遍历的核心问题是:二维结构的线性化
而层次遍历可以同时遍历左,右结点。
储存结构:堆栈,队列
队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队,访问该结点,其左右结点入队。
s
层序基本过程:先根结点入队,然后:
- 从队列中取出一个元素;
- 访问该元素所指结点;
- 若该元素所指结点的左,右孩子结点非空,则将其左右孩子的指针顺序入队。
void LevelOerderTraversal(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);
}
}
3. 二叉搜索树
满足:
例如:
二叉搜索树的查找操作:Find
- 查找从根结点开始,如果树为空,返回NULL
- 若搜索树非空,则根结点关键字和X进行比较,并进行不同处理:
- 若X小于根结点键值,只需在左子树中继续搜索;
- 若X大于根结点的键值,在右子树中进行继续搜索;
- 若相等,搜索完成,return该值;
/*二叉搜索树的查找操作*/
Position IterFind(ELementType X,BinTree BST)
{
while(BST)
{
if(X > BST->Data)
BST = BST->Right;
else if(X < BST ->Data)
BST = BST->Left;
else /*X == BST->Data;*/
return NULL;
}
}
查找最大和最小元素
/*查找最大值的迭代函数*/
Position FinMax(BinTree BST)
{
if(BST)
while(BST->Right)
BST = BST->Right;
/*沿右分支继续查找明知道最右叶结点*/
return BST;
}
/*查找最小元素的递归函数*/
Position FindMin(BinTree BST)
{
if(!BST) return NULL;
else if (!BST->Left)
return BST;
else
return FindMin(BST->Left);
}
二叉搜索树的插入
【分析】:关键是要找到元素应该插入的位置,可以采用与Find类似的方法
/*二叉搜索树的插入*/
BinTree Insert(ELementType X,BinTree BST)
{
if (!BST)
{/* 如原树为空,生成并返回一个结点的二叉搜索树*/
BST = malloc(sizeof(struct TreeNode));
BST->Data = X;
BST->Left = BST->Right = NULL;
}
else /*开始找要插入元素的位置*/
if(X<BST->Data)
BST->Left = Insert(X,BST->Right);
/*递归插入左子树*/
else if(X>BST->Data)
BST->Right = Insert(X,BST->Right);
/*递归插入*子树*/
return BST;
}
二叉搜索树的删除
考虑三种情况
- 要删除的是叶结点:直接删除,并再修改其父结点指针–置为NULL
- 要删除的结点只有一个孩子结点:将其父结点的指针指向要删除结点的孩子结点
- 要删除的结点有左,右两棵子树;用另一结点替代被删除结点:右子树的最小元素或左子树的最大元素
/*二叉搜索树的删除*/
BinTree Delete(ELementType X,BinTree BST)
{
Position Tmp;
if(!BST) pintf("未找到");
else if(X < BST->Data)
BST->Left = Delete(X,BST->Left);/*左子树递归删除*/
else if(X > BST->Right)
BST ->Right = Delete(X,BST->Right);/*右子树递归删除*/
else
if(BST->Left && BST->Right){ /*被删除结点有左右两个子结点*/
Tmp = FindMin(BST->Right);
/*在右子树中找最小的元素填充删除结点*/
BST->Data = Tmp->Data;
BST->Right = Delete(BST->Data,BST->Right);
/*在删除结点的右子树删除最小元素*/
}else{ /*被删除结点有一个或无子结点*/
Tmp = BST;
if(!BST->Left) /*有右孩子或无子结点*/
BST = BST->Right;
else if(!BST->Right) /*有左孩子或无子结点*/
BST = BST-> Left;
free(Tmp);
}
return BST;
}
学习来源
学习自中国mooc浙江大学的数据结构这一课程:
https://www.icourse163.org/learn/ZJU-93001?tid=120001#/learn/announce