基本概念
二叉排序树,又称二叉查找树,一棵二叉树或者是空二叉树,或者是具有如下特质的二叉树
1.左子树上所以的结点的关键字均小于根结点的关键字
2.右子树上所有结点的关键字均大于根结点的关键字
3.左子树和右子树又各是一棵二叉排序树
左子树结点值 < 根结点值 < 右子树结点值
进行中序遍历,可以得到一个递增的有序序列
二叉排序树可用于元素的有序组织、搜索
查找操作
1.若树非空,目标值与根结点的值比较
2.若相等,则查找成功
3.若小于根结点,则在左子树上查找,否则在右子树上查找
4.查找成功,返回结点指针,查找失败返回NULL
相关代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| typedef struct BSTNode { int key; struct BSTNode *lchild, *rchild; }BSTNode, *BSTree;
BSTNode *BST_Search(BSTree T, int key) { while (T != NULL && key != T->key) { if (key < T->key) { T = T->lchild; } else { T = T->rchild; } } return T; }
|
最坏时间复杂度: O(1)
递归实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| typedef struct BSTNode { int key; struct BSTNode *lchild, *rchild; }BSTNode, *BSTree;
BSTNode *BSTSearch(BSTree T, int key) { if (T == NULL) { return NULL; } if (key == T->key) { return T: } else if (key < T->key) { return BSTSearch(T->lchild, key); } else { return BSTSearch(T->rchild, key); } }
|
最坏空间复杂度: O(h)
效率分析
在查找运算中,需要对比关键字的次数称为查找长度,反应了查找操作的时间复杂度。若树高h,找到最下层的一个结点需要对比h次
最好情况:
n个结点的二叉树最小高度为[log2n + 1],平均查找长度=O(long2n)
最坏情况:
每个结点只有一个分支,树高h=结点数n。平均查找长度=O(n)
平均查找长度
英文缩写ASL,值为单层结点树乘以层序号(1,2,3,…)在把每层的值加起来除以结点数
graph TD;
A(("50"));
B(("26"));
C(("66"));
D(("21"));
E(("30"));
F(("60"));
G(("70"));
H(("68"));
A-->B;
A-->C;
B-->D;
B-->E;
C-->F;
C-->G;
G-->H;
G-->N(( ));
style N fill:#f100,stroke-width:0px
linkStyle 7 stroke:#0ff,stroke-width:0px
查找成功ASL = (1x1 + 2x2 + 3x4 + 4x1)/8 = 2.625
graph TD;
A(("50"));
B(("26"));
C(("66"));
D(("21"));
E(("30"));
F(("60"));
G(("70"));
H(("68"));
A-->B;
A-->C;
B-->D;
B-->E;
C-->F;
C-->G;
D-.-R1[ ];
D-.-R2[ ];
E-.-R3[ ];
E-.-R4[ ];
F-.-R5[ ];
F-.-R6[ ];
G-->H;
G-.-R7[ ];
H-.-R8[ ];
H-.-R9[ ];
倒数第二层需要对比3次,共有7个结点
倒数第一层需要对比4次,共有2个结点
查找失败ASL = (3x7 + 4x2)/9 = 3.22
插入操作
若原二叉排序树为空,则直接插入结点。否则,若关键字k小于根结点值,则插入到左子树,若关键字k大于根结点值,则插入到右子树
相关代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int BST_Insert(BSTree &T, int k) { if (T == NULL) { T = (BSTree)malloc(sizeof(BSTNode)); T->key = k; T->lchild = T->rchild = NULL; return 1; } else if (k == T->key) { return 0; } else if (k < T->key) { return BST_Insert(T->lchild, k); } else { return BST_Insert(T->rchild, k); } }
|
最坏空间复杂度:O(h)
构造操作
根据相关数组序列,构造二叉排序树
1 2 3 4 5 6 7 8
| void Creat_BST(BSTree &T, int str[], int n) { T = NULL; int i = 0; while (i < n) { BST_Insert(T, str[i]); i++; } }
|
不同的关键字序列可能得到同款二叉排序树
str1 = {50, 66, 26, 21, 30, 70, 68}
str2 = {50, 26, 21, 30, 66, 70, 68}
删除操作
先搜索找到目标结点
1.若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质
2.若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置
3.若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一种或第二种情况
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include<stdio.h> #include<stdlib.h> typedef struct BSTNode { int key; struct BSTNode *lchild, *rchild; }BSTNode, *BSTree;
BSTNode *BST_Search(BSTree T, int key) { while (T != NULL && key != T->key) { if (key < T->key) { T = T->lchild; } else { T = T->rchild; } } return T; }
int BST_Insert(BSTree &T, int k) { if (T == NULL) { T = (BSTree)malloc(sizeof(BSTNode)); T->key = k; T->lchild = T->rchild = NULL; return 1; } else if (k == T->key) { return 0; } else if (k < T->key) { return BST_Insert(T->lchild, k); } else { return BST_Insert(T->rchild, k); } }
void Creat_BST(BSTree &T, int str[], int n) { T = NULL; int i = 0; while (i < n) { BST_Insert(T, str[i]); i++; } }
void visit(BSTree root) { printf("%d ", root->key); }
void midOrder(BSTree T) { if (T != NULL) { midOrder(T->lchild); visit(T); midOrder(T->rchild); } }
void DeleteBST(BSTNode* T, int key) { BSTNode* p = T; BSTNode* f = NULL; BSTNode* q = NULL; while (p) { if (key == p->key) { break; } f = p; if (key < p->key) { p = p->lchild; } else { p = p->rchild; } } if (!p) { return; } q = p; if ((p->lchild) && (p->rchild)) { BSTNode* s = p->lchild; q = p; while (s->rchild) { q = s; s = s->rchild; } p->key = s->key; if (q != p) { q->rchild = s->lchild; } else { q->lchild = s->lchild; } delete(s); return; } else if (p->lchild) { q = p; p = p->lchild; } else if (p->rchild) { q = p; p = p->rchild; } else if (!p->lchild && !p->rchild) { q = p; p = NULL; } if (!f) { T = p; } else if (q == f->lchild) { f->lchild = p; } else if (q == f->rchild) { f->rchild = p; } delete(q); }
int main(void) { int str1[] = {50, 66, 26, 21, 30, 70, 68}; BSTree T; BSTNode *node; int n = sizeof(str1) / 4; Creat_BST(T, str1, n); node = BST_Search(T, 66); printf("node key is=%d\n", node->key); midOrder(T); printf("\n"); DeleteBST(T, 68); midOrder(T); return 0; }
|