引子:二分查找
int BinarySearch(List tbl,ElementType k)
{
int left,right,mid,NoFound = -1;
left = 0;
right = tbl->length - 1;
while (left <= right) {
mid = (left + right)/2;
if(k < tbl->data[mid])
right = mid - 1;
else if (k > tbl->data[mid])
left = mid + 1;
else
return mid;
}
return NoFound;
}
树
树(Tree): n(n>0)个节点构成的集合。
当n=0时,为空树。
对于一棵非空树(n>0),它具有一下性质:
- 树中有一个称为“根(Root)”的特殊结点,用r表示;
- 其余结点可分为m(m>0)个互不相交的有限集T1,T2,..,Tm,其中每个集合本身又是一棵树,称为原来树的“子树(SubTree)'
- n个节点的树有n-1个边
树的一些基本术语:
- 结点的度(Degree):结点的子树个数
- 树的度:树的所有结点中最大的度数
- 叶结点 (Leaf):度为0的结点
- 父结点 (Parent):有子树的结点是其子树
的根结点的父结点 - 子结点 (Child):若A结点是B结点的父结
点,则称B结点是A结点的子结点;子结点也称孩子结点。 - 兄弟结点(Sibling):具有同一父结点的各
结点彼此是兄弟结点。 - 路径和路径长度:从结点n,到n的路径为一
个结点序列n1,n2 ,… ,n ,n是 n+的父结点。路径所包含边的个数为路径的长度。 - 祖先结点(Ancestor):沿树根到某一结点路
径上的所有结点都是这个结点的祖先结点。 - 子孙结点(Descendant):某一结点的子树
中的所有结点是这个结点的子孙。 - 结点的层次(Level):规定根结点在1层,其它任一结点的层数是其父结点的层数加1。12.树的深度(Depth):树中所有结点中的最大层次是这棵树的深度。
二叉树
二叉树T: 一个有穷的结点集合。
这个集合可以为空
若不为空,则它是由根结点和称为其左子树T和右子树T的两个不相交的二叉树组成。
1. 特殊的二叉树
-
斜二叉树
斜二叉树 -
满二叉树:一棵深度为k且有2n-1个节点的二叉树
满二叉树 -
完全二叉树:一棵深度为k有n个节点的二叉树,当且仅当每个节点的编号与深度为k的满二叉树中的编号一一对应的二叉树
完全二叉树
2. 二叉树的几个性质
- 一个二叉树第i层最多有2i-1个结点(i>=1)
- 深度为k的二叉树最大结点数为2k -1 (k>=1)
- 对于任何非空二叉树T, n0表示叶子结点个数,n2表示度为2的非叶子结点个数,那么满足n0 = n2 + 1;
3. 二叉树的存储结构
1. 顺序存储结构
但是对于一般二叉树来说如果补全空缺位,改成完全二叉树之后在存储会造成空间浪费。
2. 链式存储结构
4. 二叉树的遍历
1. 先序遍历
1. 访问根结点
2. 先序访问左子树
3. 先序访问右子树
1. 递归遍历
void PreOrserTraversal(BinTree BT)
{
if(BT){
printf("%d",BT->data);
PreOrserTraversal(BT->left);
PreOrserTraversal(BT->right);
}
}
2. 非递归遍历
void PreOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack s = CreateStack(MAXSIZE);
while (T || !IsEmpty(s)) {
if(T){
Push(T);
printf("%d",T->data);
T = T->left;
}else{
T = Pop(s);
T -> right;
}
}
}
2. 中序遍历
1. 中序访问左子树
2. 访问根结点
3. 中序访问右子树
1. 递归遍历
void InOrderTraversal(BinTree BT)
{
if(BT){
InOrderTraversal(BT->left);
printf("%d",BT->data);
InOrderTraversal(BT->right);
}
}
2. 非递归遍历
void InOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack s = CreateStack(MAXSIZE);
while (T || !IsEmpty(s)) {
if(T){
Push(T);
T = T->left;
}else{
T = Pop(s);
printf("%d",T->data);
T = T->right;
}
}
}
3. 后序遍历
1. 后序访问左子树
2. 后序访问右子树
3. 访问根结点
1. 递归遍历
void PostOrderTraversal(BinTree BT)
{
if(BT){
PostOrderTraversal(BT->left);
PostOrderTraversal(BT->right);
printf("%d",BT->data);
}
}
2. 非递归遍历
void PostOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack s = CreateStack(MAXSIZE);
while (T || !IsEmpty(s)) {
if(T){
Push(T);
T = T->left;
}else{
T = Pop(s);
if(T->right == NULL || T->flag == 1){
printf("%d",T->data);
T = NULL;
}else{
Push(T);//重新入栈
T->flag == 1; // flag表示已经访问过右子树了
T = T->right;
}
}
}
}
4. 层序遍历
1. 先将根结点入队列
2. 从队列中取出结点并访问
3. 然后将该结点的所有非空子结点入队列
void LevelOrderTraversal(Bin�Tree BT)
{
Queue Q;
BinTree T;
if(!BT) return;
Q = CreateQueue(MAXSIZE);
EnQueue(Q, BT);
while (!IsEmpty(Q)) {
T = DeQueue(Q);
printf("%d",T->data);
if(T->left) EnQueue(Q,T->left);
if(T->right) EnQueue(Q, T->right);
}
}
5. 遍历应用例子
1. 遍历二叉树中的叶子结点
void PreOrserTraversal(BinTree BT)
{
if(BT){
if(!BT->left && !BT->right)
printf("%d",BT->data);
PreOrserTraversal(BT->left);
PreOrserTraversal(BT->right);
}
}
- 这个例子也可以用中序和后序
2. 求二叉树的高度
int PostOrderGetHeight(BinTree BT)
{
int Max, HL, HR;
if(BT){
HL = PostOrderGetHeight(BT->left);
HR = PostOrderGetHeight(BT->right);
Max = HL > HR ? HL : HR;
return Max + 1;
}
return 0;
}
6. 二叉树同构问题
给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。现给定两棵树,请你判断它们是否是同构的。
1. 二叉树静态链表表示
2. 建二叉树
Tree BuildTree(struct TreeNode T[])
{
int N, Root = Null;
char cl,cr;
scanf("请输入结点个数:%d\n",&N);
int *check = (int *)malloc(N*sizeof(int));
if(N){
for (int i = 0; i<N; i++) check[i] = 0;
for (int i = 0; i<N; i++) {
scanf("%c,%c,%c\n",&T[i].Element,&cl,&cr);
if(cl != '-'){
T[i].left = cl - '0';
check[T[i].left] = 1;
}else{
T[i].left = Null;
}
if(cr != '-'){
T[i].right = cr - '0';
check[T[i].right] = 1;
}else{
T[i].right = Null;
}
}
for (int i = 0; i<N; i++) {
if(!check[i]) break;
}
Root = i;
}
return Root; //返回根结点索引
}
3. 判定同构
int Isomorphic(Tree R1,Tree R2)
{
if(R1==Null && R2==Null)
return 1;
if((R1==Null && R2!=Null) || (R1!=Null && R2==Null))
return 0;
if(T1[R1].Element != T2[R2].Element)
return 0;
if(T1[R1].left == Null && T2[R2].left == Null)
return Isomorphic(T1[R1].right,T2[R2].right);
if((T1[R1].left != Null && T2[R2].left != Null)&&
(T1[T1[R1].left].Element == T2[T2[R2].left].Element))
return Isomorphic(T1[R1].left,T2[R2].left)&&Isomorphic(T1[R1].right,T2[R2].right);
else
return Isomorphic(T1[R1].left,T2[R2].right)&&Isomorphic(T1[R1].right,T2[R2].left);
}
二叉搜索树
二叉搜索树: 一棵二叉树,可以为空;如果不为空,满足以下性质:
- 非空左子树的所有键值小于其根结点的键值。
- 非空右子树的所有键值大于其根结点的键值。
- 左、右子树都是二叉搜索树。
二叉搜索树操作的特别函数:
- Position Find( ElementType X, BinTree BST):从二叉搜索树BST中查找元素X,返回其所在结点的地址;
- Position FindMin( BinTree BST):从二叉搜索树BST中查找并返回最小元素所在结点的地址;
- Position FindMax( BinTree BST):从二叉搜索树BST中查找并返回最大元素所在结点的地址。
- BinTree Insert(ElementType X, BinTree BST )
- BinTree Delete(ElementType X, BinTree BST )
1. 递归查找法
Position Find( ElementType X, BinTree BST)
{
if(!BST) return NULL;
if(X > BST->Data)
return Find(X, BST->Right);
else if(X < BST->Data)
return Find(X, BST->Left);
else
return BST;
}
2. 非递归查找法
Position IterFind(ElementType X, BinTree BST)
{
while (BST) {
if(X > BST->Data)
BST = BST->Right;
else if (X < BST->Data)
BST = BST->Left;
else
return BST;
}
return NULL;
}
3. 查找最小元素 递归法
Position FindMin( BinTree BST)
{
if(!BST)
return NULL;
else if (!BST->Left)
return BST;
else
return FindMin(BST->Left);
}
4. 查找最大元素 非递归法
Position FindMax( BinTree BST)
{
if(BST)
while (BST->Right) {
BST = BST->Right
}
return BST;
}
5. 递归插入
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->Left);
else if (X > BST->Data)
BST->Right = Insert(X, BST->Right)
return BST;
}
二叉搜索树的删除
考虑三种情况:
- 要删除的结点是叶子结点:直接删除,并将父结点指针置为NULL
- 要删除的结点有一个孩子结点:删除该结点,并将父结点的指针指向这个孩子结点
- 要删除的结点有左右子树:用另一个结点替代被删除的结点:左子树最大元素或右子树的最小元素
BinTree Delete(ElementType X, BinTree BST )
{
BinTree Tmp;
if(!BST)
printf("要删除的元素未找到");
else if(X < BST->Data)
BST->Left = Delete(X, BST->Left);
else if (X > BST->Data)
BST->Right = Delete(X, BST->Right);
else if (BST->Left && BST->Right){
Tmp = FindMin(BST->Right);
BST->Data = Tmp->Data;
BST->Right = Delete(Tmp->Data, BST->Right);
}else{
Tmp = BST;
if(!BST->Left)
BST = BST->Right;
else if (!BST->Right)
BST = BST->Left;
free(Tmp);
}
return BST;
}
平衡二叉树
- 可以看出(b)的查找效率最高,越平衡的树查找效率越高。
平衡因子(Balance Factor 简称:BF): BF = hL - hR , hL hR 分别为左右子树高度。
平衡二叉树(AVL树): 空树,或者任意左右子树的高度差绝对值不超过1,即|BF(T)|<=1。
平衡二叉树的调整
LL旋转
LR旋转
RR旋转
RL旋转
1. 判断二叉树是否平衡
bool noBalance = false;
struct TreeNode *rjt = NULL;
int checkTreeBalance(struct TreeNode *root)
{
if(NULL == root) return 0;
int l = checkTreeBalance(root->left);
int r = checkTreeBalance(root->right);
if(noBalance) return 0;
int dif = abs(l - r);
if(dif > 1){
noBalance = true;
rjt = root;
}
return l > r ? l + 1 : r + 1;
}
2. 父结点查询
TreeNode* queryTopData(TreeNode *root, int data)
{
TreeNode *top = NULL;
TreeNode *tmp = root;
while (tmp != NULL) {
if(data == tmp->data){
return top;
}
top = tmp;
if(data > tmp->data)
tmp = tmp->right;
else if(data < tmp->data)
tmp = tmp->left;
}
return NULL;
}
3. 左左旋转
//不平衡二叉树
70
/ \
50 80
/ \
40 60
/
30
// 左左旋转后的二叉树
50
/ \
40 70
/ / \
30 60 80
bool rotateLL(TreeNode **root, TreeNode *notBalanceRoot)
{
if(*root != notBalanceRoot){
printf("左左旋转,非根结点");
//查找不平衡结点的父结点
TreeNode *fNode = queryTopData(*root,notBalanceRoot->data);
if(fNode == NULL) return false;
TreeNode *left = notBalanceRoot->left;
TreeNode *lright = left->right;
left->right = notBalanceRoot;
notBalanceRoot->left = lright;
if(notBalanceRoot == fNode->left)
fNode->left = left;
else if (notBalanceRoot == fNode->right)
fNode->right = left;
return true;
}else{
printf("左左旋转,根结点");
TreeNode *left = notBalanceRoot->left;
TreeNode *lright = left->right;
left->right = notBalanceRoot;
*root->left = lright;
*root = left;
return true;
}
}
4. 左右旋转
//不平衡二叉树
70
/ \
50 80
/ \
40 60
/
55
//左右旋转后的二叉树
60
/ \
50 70
/ \ \
40 55 80
bool rotateLR(TreeNode **root, TreeNode *notBalanceRoot)
{
if(*root != notBalanceRoot){
printf("左右旋转,非根结点");
TreeNode *fNode = queryTopData(*root,notBalanceRoot->data);
if(fNode == NULL) return false;
TreeNode *left = notBalanceRoot->left;
TreeNode *lright = left->right;
TreeNode *lrightLeft = lright->left;
TreeNode *lrightRight = lright->right;
lright->left = left;
lright->right = notBalanceRoot;
left->right = lrightLeft;
notBalanceRoot->left = lrightRight;
if(notBalanceRoot == fNode->left)
fNode->left = lright;
else if (notBalanceRoot == fNode->right)
fNode->right = lright;
return true;
}else{
printf("左右旋转,根结点");
TreeNode *left = notBalanceRoot->left;
TreeNode *lright = left->right;
TreeNode *lrightLeft = lright->left;
TreeNode *lrightRight = lright->right;
lright->left = left;
lright->right = notBalanceRoot;
left->right = lrightLeft;
notBalanceRoot->left = lrightRight;
*root = lright;
return true;
}
5. 右右旋转
//不平衡的二叉树
70
/ \
50 80
/ \
75 88
/
85
//右右旋转的二叉树
80
/ \
70 88
/ \ /
50 75 85
bool rotateRR(TreeNode **root, TreeNode *notBalanceRoot)
{
if(*root != notBalanceRoot){
printf("右右旋转,非根结点");
TreeNode *fNode = queryTopData(*root,notBalanceRoot->data);
if(fNode == NULL) return false;
TreeNode *right = notBalanceRooot->right;
TreeNode *rleft = right->left;
right->left = notBalanceRoot
notBalanceRoot->right = rleft;
if(notBalanceRoot == fNode->left)
fNode->left = right;
else if(notBalanceRoot == fNode->right)
fNode->right = right;
return true;
}else{
printf("右右旋转,根结点");
TreeNode *right = notBalanceRooot->right;
TreeNode *rleft = right->left;
right->left = notBalanceRoot
notBalanceRoot->right = rleft;
*root = right;
return true;
}
}
6. 右左旋转
//不平衡二叉树
70
/ \
50 80
/ \
75 88
\
77
//右左旋转后的二叉树
75
/ \
70 80
/ / \
50 77 88
bool rotateRL(TreeNode **root,TreeNode *notBalanceRoot)
{
if(*root != notBalanceRoot){
printf("右左旋转,非根结点");
TreeNode *fNode = queryTopData(*root,notBalanceRoot->data);
if(fNode == NULL) return false;
TreeNode *right = notBalanceRoot->right;
TreeNode *rleft = right->left;
TreeNode *rleftLeft = rleft->left;
TreeNode *rleftRight = rleft->right;
rleft->left = notBalanceRoot;
rleft->right = right;
notBalanceRoot->right = rleftLeft;
right->left = rleftRight;
if(notBalanceRoot == fNode->left)
fNode->left = rleft;
else if (notBalanceRoot == fNode->right)
fNode->right = rleft;
return true;
}else{
printf("右左旋转,根结点");
TreeNode *right = notBalanceRoot->right;
TreeNode *rleft = right->left;
TreeNode *rleftLeft = rleft->left;
TreeNode *rleftRight = rleft->right;
rleft->left = notBalanceRoot;
rleft->right = right;
notBalanceRoot->right = rleftLeft;
right->left = rleftRight;
*root = rleft;
return true;
}
}