伸展樹的優點:1、數據結構較簡單,不需要保存AVL平衡相關信息,可以節省空間
2、不存在壞的輸入序列,它可以保證任意連續M次對樹的操作最多花費O(M log N)時間
3、一棵伸展樹每次操作的攤還時間爲O(log N)
伸展樹的基本思想:當一個基點被訪問後,它就要經過一系列旋轉處理,直至將該節點放到根上,便於下次再次訪問。
#include<stdio.h>
#include<stdlib.h>
struct splay_tree {
char data;
struct splay_tree *lchild;
struct splay_tree *rchild;
struct splay_tree *parent;//爲了便於尋找其父節點及其祖父節點,故添加一個前向類型指針
};
struct splay_tree *global_X;//爲了記錄插入位置,故添加一個全局指針
//zig-zag format
//P是X的父節點,G是X的祖父節點
struct splay_tree *zig_zag_rotate(struct splay_tree *X, struct splay_tree *P, struct splay_tree *G)
{
// G
//P
// X
if((X->data > P->data) && (P->data < G->data))
{
P->rchild = X->lchild;
G->lchild = X->rchild;
X->lchild = P;
X->rchild = G;
X->parent = G->parent;
P->parent = X;
G->parent = X;
}
//G
// P
//X
if((X->data < P->data) && (P->data > G->data))
{
P->lchild = X->rchild;
G->rchild = X->lchild;
X->rchild = P;
X->lchild = G;
X->parent = G->parent;
P->parent = X;
G->parent = X;
}
return X;
}
//zig-zig format
//P是X的父節點,G是X的祖父節點
struct splay_tree *zig_zig_rotate(struct splay_tree *X, struct splay_tree *P, struct splay_tree *G)
{
// G
// P
//X
if((X->data < P->data) && (P->data < G->data))
{
G->lchild = P->rchild;
P->rchild = G;
P->lchild = X->rchild;
X->rchild = P;
X->parent = G->parent;
P->parent = X;
G->parent = P;
}
//G
// P
// X
if((X->data > P->data) && (P->data > G->data))
{
G->rchild = P->lchild;
P->lchild = G;
P->rchild = X->lchild;
X->lchild = P;
X->parent = G->parent;
P->parent = X;
G->parent = P;
}
return X;
}
//zig format
struct splay_tree *zig_rotate(struct splay_tree *X, struct splay_tree *P)
{
// P
//X
if(X->data < P->data)
{
P->lchild = X->rchild;
X->rchild->parent = P;
X->parent = P->parent;
X->rchild = P;
P->parent = X;
}
//P
// X
if(X->data > P->data)
{
P->rchild = X->lchild;
X->lchild->parent = P;
X->parent = P->parent;
X->lchild = P;
P->parent = X;
}
return X;
}
//構建一顆二叉查找樹
struct splay_tree *insert_binary_search_tree(struct splay_tree *T,char c)
{
if(NULL == T)
{
T = malloc(sizeof(struct splay_tree));
if(NULL == T)
{
printf("Failed: no memory to malloc!\n");
return NULL;
}
T->data = c;
T->lchild = NULL;
T->rchild = NULL;
T->parent = NULL;
global_X = T;
}
else
{
if(c < T->data)
{
T->lchild = insert_binary_search_tree(T->lchild,c);
if(T->lchild)
T->lchild->parent = T;
}
else if(c > T->data)
{
T->rchild = insert_binary_search_tree(T->rchild,c);
if(T->rchild)
T->rchild->parent = T;
}
else
printf("%d is already in current tree\n",c);
}
return T;
}
struct splay_tree *process_splay_tree(struct splay_tree *T)
{
struct splay_tree *X,*P,*G;
if(NULL == T)
return NULL;
if(NULL == T->parent)
return T;
if(NULL == T->parent->parent)
{
X = T;
P = T->parent;
T = zig_rotate(X,P);
}
else
{
X = T;
P = T->parent;
G = P->parent;
while(NULL != X && NULL != P && NULL != G)
{
if((X->data < P->data)&&(P->data < G->data))
T = zig_zig_rotate(X,P,G);
else if((X->data > P->data)&&(P->data < G->data))
T = zig_zag_rotate(X,P,G);
else if((X->data < P->data)&&(P->data > G->data))
T = zig_zag_rotate(X,P,G);
else if((X->data > P->data)&&(P->data > G->data))
T = zig_zig_rotate(X,P,G);
X = T;
P = T->parent;
if(NULL == P)
break;
G = P->parent;
}
if(NULL == G)
{
T = zig_rotate(X,P);
return;
}
}
return T;
}
struct splay_tree *find_splay_tree(struct splay_tree *T,char c)
{
if(NULL == T)
{
printf("Not Found: there isn't' %c in current tree\n",c);
return T;
}
if(c < T->data)
return find_splay_tree(T->lchild,c);
else if(c > T->data)
return find_splay_tree(T->rchild,c);
else
{
printf("Found: there is %c in current tree\n",c);
T = process_splay_tree(T);
return T;
}
}
struct splay_tree *insert_splay_tree(struct splay_tree *T,char c)
{
T = insert_binary_search_tree(T,c);
T = process_splay_tree(global_X);
return T;
}
struct splay_tree *find_max_binary_search_tree(struct splay_tree *T)
{
if(NULL == T)
return T;
while(NULL != T->rchild)
T = T->rchild;
return T;
}
struct splay_tree *delete_splay_tree(struct splay_tree *T,char c)
{
struct splay_tree *find_temp;
struct splay_tree *find_max_temp;
find_temp = find_splay_tree(T,c);
//判斷所要刪除的字符是否在當前樹中
if(find_temp)
{
//先找到左子樹中的最大值位置
find_max_temp = find_max_binary_search_tree(find_temp->lchild);
//將最大值放到根上
find_temp->lchild->parent = NULL;//將左子樹的根的parent設置爲NULL,否則會影響後面的操作
find_max_temp = find_splay_tree(find_temp->lchild,find_max_temp->data);
//將原右子樹合併到根上
find_max_temp->rchild = find_temp->rchild;
return find_max_temp;
}
//如果所有刪除的字符不在當前樹中,提示用戶並返回
else
{
printf("Delete failed: there isn't %c in current tree\n",c);
return T;
}
}
void print_preorder(struct splay_tree *T)
{
if(NULL == T)
return;
printf("%c ",T->data);
print_preorder(T->lchild);
print_preorder(T->rchild);
}
void print_midorder(struct splay_tree *T)
{
if(NULL == T)
return;
print_midorder(T->lchild);
printf("%c ",T->data);
print_midorder(T->rchild);
}
void print_postorder(struct splay_tree *T)
{
if(NULL == T)
return;
print_postorder(T->lchild);
print_postorder(T->rchild);
printf("%c ",T->data);
}
void print_allorder(struct splay_tree *T)
{
print_preorder(T);
printf("\n");
print_midorder(T);
printf("\n");
print_postorder(T);
printf("\n");
}
int main(void)
{
char c;
struct splay_tree *T = NULL;
struct splay_tree *temp = NULL;
scanf("%c",&c);
while(c != '#')
{
T = insert_binary_search_tree(T,c);
scanf("%c",&c);
}
print_allorder(T);
//測試find操作
getchar();
printf("請輸入查找的字符:");
scanf("%c",&c);
printf("-----start----find-%c---------\n",c);
temp = find_splay_tree(T,c);
if(temp)
T = temp;
printf("-----end----find---%c------\n",c);
print_allorder(T);
//測試insert操作
getchar();
printf("請輸入插入的字符:");
scanf("%c",&c);
printf("-----start----insert---%c---------\n",c);
T = insert_splay_tree(T,c);
printf("-----end------insert---%c---------\n",c);
print_allorder(T);
//測試delete操作
getchar();
printf("請輸入刪除的字符:");
scanf("%c",&c);
printf("-----start----delete---%c---------\n",c);
T = delete_splay_tree(T,c);
printf("-----end------delete---%c---------\n",c);
print_allorder(T);
return 0;
}
運行結果如下: