1.二叉搜索树
《数据结构与算法分析》一书中已经说过(p85)“不过,在没有使用删除或是懒惰删除的情况下,可以证明所有二叉查找树是等可能出现的,而且我们可以断言,上述那些操作的平均时间都是O(logN)”
先说结论,再没有删除的情况下,10万次的万次随机插入后10万次的万次访问操作的单次操作平均时间是O(logN)。
其中尽管出现了明显不平衡的树,但是上述结论依然适用。
为什么呢?
个人以为差距所在处为左右子节点的数量比率上,以一颗含有N个节点的二叉搜索树为例,除去根节点,左右子节点的数量比率越靠近常数级越好,越靠近O(n)越不妙。如果这棵树所有节点的比率都趋近于第二种情况,那么这棵树就会变成昂贵的单链表,它的单次操作平均时间将是O(N),但是这种概率就和这棵树所有节点的比率都趋近于第一种情况一样,即完美二叉树,概率极低。所以在这棵树中所有节点的比率大多出现在一二种情况中间,然而对树的深度起决定影响的是第二种情况的节点数量,如前所述,第二种情况的节点数量在随机插入N次的树中占比率极低,这也就是为什么随机插入N次的二叉树的节点平均深度能在O(logN),而不是O(N),所以结论单次操作平均时间是O(logN)成立。
以下给出二叉搜索树的代码实现(建议能人们自己敲,我的看看就行)
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
//11.28,二叉搜索树的实现与测试
typedef int Elem;
int count = 0;
typedef struct Treenode {
Elem data;
int deletion;
//struct Treenode* parents;
struct Treenode* leftchild;
struct Treenode* rightchild;
}Treenode;
typedef Treenode* Treepoint;
static Treepoint MakeEmpty(Treepoint root) {
if (root != NULL) {
MakeEmpty(root->leftchild);
MakeEmpty(root->rightchild);
free(root);
}
return NULL;
}
static Treepoint Find(Treepoint root, Elem x) {
count++;
if (root == NULL)
return NULL;
if (x < root->data) {
count++;
return Find(root->leftchild, x);
}
else if (x > root->data) {
count++;
return Find(root->rightchild, x);
}
else
return root;
}
static Treepoint FindMin(Treepoint root) {
if (root == NULL)
return NULL;
else if (root->leftchild == NULL)
return root;
else
return FindMin(root->leftchild);
}
static Treepoint FindMax(Treepoint root) {
if (root == NULL)
return NULL;
else if (root->rightchild == NULL)
return root;
else
return FindMin(root->rightchild);
}
static Treepoint Insert(Treepoint root, Elem x) {
if (root == NULL) {
root = (Treepoint)calloc(1, sizeof(Treenode));
if (root != NULL) {
root->data = x;
root->deletion = 1;
root->leftchild = NULL;
root->rightchild = NULL;
}
}
else {
if (x < root->data)
root->leftchild = Insert(root->leftchild, x);
else if (x > root->data)
root->rightchild = Insert(root->rightchild, x);
else
root->deletion++;
}
return root;
}
static Treepoint Delete(Treepoint root, Elem x) {
if (root == NULL)
printf("Error!");
else if (x < root->data)
root->leftchild = Delete(root->leftchild, x);
else if (x > root->data)
root->rightchild = Delete(root->rightchild, x);
else {
root->deletion--;
}
return root;
}
static void middle(Treepoint root) {
if (root != NULL) {
if (root->leftchild != NULL)
middle(root->leftchild);
if(root->deletion > 0)
printf("%d(deletion:%3d) ", root->data,root->deletion);
//else
//printf("%d(deletion:%3d) ", root->data, root->deletion);
if (root->rightchild != NULL)
middle(root->rightchild);
}
}
void test() {
Treepoint root = Insert(NULL,1);//树的初始化
//测试代码大家可自行编写,我的仅供参考
srand((unsigned int)time(NULL));
const int m = 100000;
const int m2 = 100000000;
int arr[m] = { 0 };
for (int i = 0;i < m;i++) {
arr[i] = rand() % m2;
}
for (int i = 0;i < m;i++) {
Insert(root, arr[i]);
}
for (int i = 0;i < m;i++) {
int k = rand() % m;
root = Find(root, arr[k]);
}
printf("\ncount = %d\n", count);
}
int main() {
test();
return 0;
}
代码仅供参考,还是那句话,佬们自己敲自己跑自己看结果。
2.二叉搜索树的优化--伸展树(splay tree)
敬请期待....(就快了)