数据结构与算法分析——c语言描述 第四章树 伸展树
看了书上的思路,全靠自己独立把代码写出来了,后来才发现书上给的代码实现是放到最后一章12章了。
写完我都为我的意志坚定而惊讶。花了一天和一个早上的一个小时。代码一定要靠自己写出来,很多时候代码一看就懂,但你是不知道怎么来的,架构思路方法怎么来的。不停debug不停修改代码就是一个创作思考的过程,don't be afraid.
说几点值得注意的
查找,插入,删除是会改变树的结构的。有时会把根节点也改变掉,所以调用的时候必须是t = findMax(t);,把返回值赋给t,当然也可以传入指针,但这样指针的地址更麻烦。旋转的时候不是每一个节点都旋转,所以返回的必须包含两个信息,要找的值和这一层的根节点,有时候相同(旋转的时候),有时候不同(不旋转的时候),所以返回一个结构体包含两个指针。
书上删除的思路假定了要找的节点必须有左子树的情况和findmax必须要最大值就是根节点。我考虑没有左子树和没有父亲的情况。
查找,找最大值,找最小值需要返回相应的节点的指针。但是树是自底向上旋转的,并且是有祖父的时候才旋转,那么再最上层的时候一定要把节点转到根节点上,不然你就会忽略上一层的节点。(t = findMax(t);)这是使用方法,也就是说必须要找的值放到第一个。插入则不需要放到根节点上。
SplayTree.h
typedef int ElementType; #ifndef _SplayTree_H #define _SplayTree_H struct SplayNode; typedef struct SplayNode *Position; typedef struct SplayNode *SplayTree; SplayTree createSplayTree(); SplayTree MakeEmpty(SplayTree T); Position find(ElementType X, SplayTree t); Position findMin(SplayTree t); Position findMax(SplayTree t); SplayTree insert(ElementType X, SplayTree t); SplayTree Delete(ElementType X, SplayTree t); ElementType retrieve(Position p); void listDirectory(SplayTree t); #endif
#include"SplayTree.h" #include<stdlib.h> #include"fatal.h" struct SplayNode { ElementType element; SplayTree left; SplayTree right; }; struct Pair {//用于返回的结构体 Position pToX; Position pToNextLevelRootNode; }; static Position singleRotateWithLeft(Position k2) { Position k1 = k2->left; Position y = k1->right; k2->left = y; k1->right = k2; return k1; } static Position singleRotateWithRight(Position k1) { Position k2 = k1->right; Position y = k2->left; k1->right = y; k2->left = k1; return k2; } static Position doubleRotateWithLeft(Position k3) { Position k1 = k3->left; k3->left = singleRotateWithRight(k1); return singleRotateWithLeft(k3); } static Position doubleRotateWithRight(Position k1) { Position k3 = k1->right; k1->right = singleRotateWithLeft(k3); return singleRotateWithRight(k1); } static Position zig_ZigRotateWithLeft(Position G) { Position P = G->left; Position X = P->left; Position B = X->right; Position C = P->right; X->right = P; P->left = B; P->right = G; G->left = C; return X; } static Position zig_ZigRotateWithRight(Position G) { Position P = G->right; Position X = P->right; Position B = P->left; Position C = X->left; X->left = P; P->left = G; P->right = C; G->right = B; return X; } SplayTree createSplayTree() { return NULL; } SplayTree MakeEmpty(SplayTree T) { if (T != NULL) { MakeEmpty(T->left); MakeEmpty(T->right); free(T); } return NULL; } static struct Pair find_internal(ElementType X, SplayTree t) { struct Pair ret;//返回上一层的包含指向X和旋转后的这层树根节点的指针的结构 struct Pair receive;//下一层返回来的,指向X和旋转后的下一层树的根节点的指针的结构 if (t == NULL) {//空树,空指针 ret.pToNextLevelRootNode = NULL; ret.pToX = NULL; } else if (X < t->element) { receive = find_internal(X, t->left); t->left = receive.pToNextLevelRootNode; if (receive.pToX == NULL) {//没找到X ret.pToNextLevelRootNode = t; ret.pToX = NULL; } else { if (t->left->left == receive.pToX) { t = zig_ZigRotateWithLeft(t); ret.pToX = ret.pToNextLevelRootNode = t; printf("%d test\n", t->element); } else if (t->left->right == receive.pToX) { t = doubleRotateWithLeft(t); ret.pToX = ret.pToNextLevelRootNode = t; } else { ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } } else if (X > t->element) { receive = find_internal(X, t->right); t->right = receive.pToNextLevelRootNode; if (receive.pToX == NULL) {//没找到X ret.pToNextLevelRootNode = t; ret.pToX = NULL; } else { if (t->right->right == receive.pToX) { t = zig_ZigRotateWithRight(t); ret.pToX = ret.pToNextLevelRootNode = t; } else if (t->right->left == receive.pToX) { t = doubleRotateWithRight(t); ret.pToX = ret.pToNextLevelRootNode = t; } else { ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } } else {//相等的情况,就是要寻找的 ret.pToX = t; ret.pToNextLevelRootNode = t; } return ret; } Position find(ElementType X, SplayTree t) { struct Pair receive; receive = find_internal(X,t); if (receive.pToNextLevelRootNode != receive.pToX)//要找的点不在根节点上,转换到根节点,在第二层 if (receive.pToX->element < receive.pToNextLevelRootNode->element) return singleRotateWithLeft(receive.pToNextLevelRootNode); else return singleRotateWithRight(receive.pToNextLevelRootNode); return receive.pToNextLevelRootNode; } struct Pair findMin_internal(SplayTree t) { struct Pair receive, ret; if (t->left) {//存在左节点 receive = findMin_internal(t->left); t->left = receive.pToNextLevelRootNode; if (t->left->left == receive.pToX) {//pToX为最小节点的指针 t = zig_ZigRotateWithLeft(t); ret.pToNextLevelRootNode = t; ret.pToX = t; } else { ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } else { ret.pToX = t; ret.pToNextLevelRootNode = t; } return ret; } Position findMin(SplayTree t) { struct Pair receive; receive = findMin_internal(t); if (receive.pToNextLevelRootNode != receive.pToX)//最大的在第二层 return singleRotateWithLeft(receive.pToNextLevelRootNode); return receive.pToNextLevelRootNode; } struct Pair findMax_internal(SplayTree t) { struct Pair receive, ret; if (t->right) {//存在左节点 receive = findMax_internal(t->right); t->right = receive.pToNextLevelRootNode; if (t->right->right == receive.pToX) {//pToX为最小节点的指针 t = zig_ZigRotateWithRight(t); ret.pToNextLevelRootNode = t; ret.pToX = t; } else { ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } else { ret.pToX = t; ret.pToNextLevelRootNode = t; } return ret; } Position findMax(SplayTree t) { struct Pair receive; receive = findMax_internal(t); if (receive.pToNextLevelRootNode != receive.pToX)//最大的在第二层 return singleRotateWithRight(receive.pToNextLevelRootNode); return receive.pToNextLevelRootNode; } static Position makeNode(ElementType X) { Position t = malloc(sizeof(struct SplayNode)); if (t == NULL) Error("OUT OF MEMORY"); t->element = X; t->left = NULL; t->right = NULL; return t; } struct Pair insert_internal(ElementType X, SplayTree t) { struct Pair ret, receive; if (t == NULL) {//找到最底层 t = makeNode(X); ret.pToX = t; ret.pToNextLevelRootNode = t; } else if (X < t->element) {//小于 receive = insert_internal(X, t->left); t->left = receive.pToNextLevelRootNode; if (t->left->left == receive.pToX) {//一字型 t = zig_ZigRotateWithLeft(t); ret.pToX = ret.pToNextLevelRootNode = t;//旋转了之后插入的节点编程这一层的根节点,下同 } else if (t->left->right == receive.pToX) {//之子型 t = doubleRotateWithLeft(t); ret.pToX = ret.pToNextLevelRootNode = t; } else {//这一层的下一个节点就是X,没必要旋转 ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } else if (X > t->element) { receive = insert_internal(X, t->right); t->right = receive.pToNextLevelRootNode; if (t->right->right == receive.pToX) { t = zig_ZigRotateWithRight(t); ret.pToX = ret.pToNextLevelRootNode = t; } else if (t->right->left == receive.pToX) { t = doubleRotateWithRight(t); ret.pToX = ret.pToNextLevelRootNode = t; } else { ret.pToX = receive.pToX; ret.pToNextLevelRootNode = t; } } else { ret.pToNextLevelRootNode = t; ret.pToX = t; } return ret; } SplayTree insert(ElementType X, SplayTree t) { return insert_internal(X, t).pToNextLevelRootNode; } SplayTree Delete(ElementType X, SplayTree t) { Position father = NULL; Position p = t; while (p) { if (X < p->element) { father = p; p = p->left; } else if (X > p->element) { father = p; p = p->right; } else//相等,找到了 break; } if (p) {//找到了 Position MaxOf_T_Left; if (p->left) {//存在左子树的情况下 MaxOf_T_Left = findMax(p->left);//把最大的放到左子树根节点上 MaxOf_T_Left->right = p->right;//连接起来 if (father) {//有父节点 if (MaxOf_T_Left->element < father->element) father->left = MaxOf_T_Left; else//大于,不存在等于 father->right = MaxOf_T_Left; } else//有左子树,没父节点 t = MaxOf_T_Left; } else {//没有左子树 if (father) {//有父节点 if (p->element < father->element) father->left = p->right;//right可能空或者不空 else//大于,不存在等于 father->right = p->right; } else//没有父节点,没有左子树 t = p->right; } free(p); } return t; } ElementType retrieve(Position p) { return p->element; } static void listDir(SplayTree t, int depth) { if (t) { int d = depth; while (d--) printf(" "); printf("%d\n", t->element); if (t->left) listDir(t->left, depth + 1); if (t->right) listDir(t->right, depth + 1); } } void listDirectory(SplayTree t) { listDir(t, 0); }
main.c
#include"SplayTree.h" #include<stdio.h> #include<stdlib.h> struct SplayNode { ElementType element; SplayTree left; SplayTree right; }; int main() { SplayTree t = createSplayTree(); for (int i = 0; i < 15; i++) t = insert(rand(), t); listDirectory(t); }