二二叉搜索树学习
写在前面的话
最近接到几所大学的学生毕业后无法登录华为签订百度,我去学习:操作系统、数据结构与算法、利器。想想自己工作2.5年月薪还不到10K,过着苦逼的码农生活,而他们一出校门就是大放光芒(最起码进入的公司就让人认为牛逼哄哄的).本人痛定思痛,决定下大功夫学习一下数据结构与算法,我想这应该是根本吧.
之前也看过数据结构,可是一看到那乱七八糟的关系,就认为还是研究一下别的东西,结果就是好多东西都是浅尝辄止,知子皮毛.
本人仅仅贴出学习过程中的代码,以及一些发杂算法函数的具体凝视,还有就是学习过程中遇到过的好的解说URL,以供自己理解和兴许的复习巩固,有不正确的地方还需指正.
学习二叉树之前总感觉非常抽象,近期看到亚嵌一个关于红黑树解说的视频用到一个命令,可以将二叉树转换成图形打印出来。感觉非常奇妙,这个工具在Linux C编程一站式学习 中有提到过,
http://www.essex.ac.uk/linguistics/external/clmt/latex4ling/trees/tree/
有关应用会在后面代码測试中有提到,我想这应该是学习二叉树的一大利器,在此提出来。
之前也看过数据结构,可是一看到那乱七八糟的关系,就认为还是研究一下别的东西,结果就是好多东西都是浅尝辄止,知子皮毛.
本人仅仅贴出学习过程中的代码,以及一些发杂算法函数的具体凝视,还有就是学习过程中遇到过的好的解说URL,以供自己理解和兴许的复习巩固,有不正确的地方还需指正.
学习二叉树之前总感觉非常抽象,近期看到亚嵌一个关于红黑树解说的视频用到一个命令,可以将二叉树转换成图形打印出来。感觉非常奇妙,这个工具在Linux C编程一站式学习 中有提到过,
http://www.essex.ac.uk/linguistics/external/clmt/latex4ling/trees/tree/
有关应用会在后面代码測试中有提到,我想这应该是学习二叉树的一大利器,在此提出来。
源代码
binarytree.h
#ifndef BINARYTREE_H #define BINARYTREE_H typedef struct node *link; /** *节点中的数据类型重定义 */ typedef unsigned char TElemType; struct node { TElemType item; link lchild, rchild; }; link init(TElemType VLR[], TElemType LVR[], int n); void pre_order(link t, void (*visit)(link)); void in_order(link t, void (*visit)(link)); void post_order(link t, void (*visit)(link)); void pprint(link t); int count(link t); int depth(link t); void destroy(link t); /** *http://www.cnblogs.com/bizhu/archive/2012/08/19/2646328.html 算法图解 * *二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树, *它或者是一棵空树;或者是具有下列性质的二叉树: *(1)若左子树不空,则左子树上全部结点的值均小于它的根结点的值; *(2)若右子树不空。则右子树上全部结点的值均大于它的根结点的值; *(3)左、右子树也分别为二叉排序树; *(4)排序二叉树的中序遍历结果是从小到大排列的. * *二叉查找树相比于其它数据结构的优势在于查找、插入的时间复杂度较低,为O(log n)。 *二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。binarytree.c* *搜索,插入,删除的复杂度等于树高,期望O(log n),最坏O(n)(数列有序,树退化成线性表) *改进版的二叉查找树能够使树高为O(logn),如SBT,AVL,红黑树等. * *程序来源于Linux C编程一站式学习 */ link bstSearch(link t, TElemType key); link bstInsert(link t, TElemType key); link bstDelete(link t, TElemType key); /** *http://baike.baidu.com/view/593144.htm?fr=aladdin *平衡二叉树 */ #endif
/* binarytree.c */ #include <stdio.h> #include <stdlib.h> #include "binarytree.h" /** *生成节点 *@param item is node value *@returns link point to new node */ static link make_node(TElemType item) { link p = malloc(sizeof *p); p->item = item; p->lchild = p->rchild = NULL; return p; } /** *释放节点 *@param link to free */ static void free_node(link p) { free(p); } /** *依据前序与中序序列来初始化二叉树 *@param VLR 前序序列 *@param LVR 中序序列 *@param n 序列中数值个数 *@returns NULL when n <= 0 *@returns link pointer to new binarytree */ link init(TElemType VLR[], TElemType LVR[], int n) { link t; int k; if (n <= 0) return NULL; for (k = 0; VLR[0] != LVR[k]; k++); t = make_node(VLR[0]); t->lchild = init(VLR+1, LVR, k); t->rchild = init(VLR+1+k, LVR+1+k, n-k-1); return t; } #ifdef RECU /** *前序遍历(跟左右) *@param t to visit *@param visit point to a func */ void pre_order(link t, void (*visit)(link)) { if (!t) return; visit(t); pre_order(t->lchild, visit); pre_order(t->rchild, visit); } /** *中序序遍历(左跟右) *@param t to visit *@param visit point to a func */ void in_order(link t, void (*visit)(link)) { if (!t) return; in_order(t->lchild, visit); visit(t); in_order(t->rchild, visit); } /** *中序序遍历(左右跟) *@param t to visit *@param visit point to a func */ void post_order(link t, void (*visit)(link)) { if (!t) return; post_order(t->lchild, visit); post_order(t->rchild, visit); visit(t); } #endif /** *遍历二叉树,生成用于tree工具的字符串 *@param root to visit */ void pprint(link root) { printf("("); if (root != NULL) { printf("%d", root->item); pprint(root->lchild); pprint(root->rchild); } printf(")"); } int count(link t) { if (!t) return 0; return 1 + count(t->lchild) + count(t->rchild); } int depth(link t) { int dl, dr; if (!t) return 0; dl = depth(t->lchild); dr = depth(t->rchild); return 1 + (dl > dr ? dl : dr); } void destroy(link t) { post_order(t, free_node); } /** *在bst中查找值为key的节点 * *1、若b是空树,则搜索失败,否则; *2、若x等于b的根节点的数据域之值。则查找成功;否则; *3、若x小于b的根节点的数据域之值。则搜索左子树;否则; *4、查找右子树. * *@param t to search *@param key the value of link to find *@returns the link of the key */ link bstSearch(link t, TElemType key) { if (t == NULL) return NULL; if (t->item > key) { return bstSearch(t->lchild, key); } else if (t->item < key){ return bstSearch(t->rchild, key); } else { return t; } } /** *在bst中插入值为key的节点 * *1、若t是空树。则将key作为根节点的值插入。否则; *2、若t->item大于key,则把key插入到左子树中,否则; *3、把key插入到左子树中. * *@param t 要插入的 bst *@param key 要插入的值 *@returns 插入后的bst */ link bstInsert(link t, TElemType key) { if (t == NULL) { return make_node(key); } if (t->item > key) { t->lchild = bstInsert(t->lchild, key); } else { t->rchild = bstInsert(t->rchild, key); } return t; } /** *在bst中删除值为key的节点 * *1、若t为空树,则直接返回NULL,否则; *2、若t->item大于key,bst左子树为bst左子树删除key后的bst,否则; *3、若t->item小于key。bst右子树为bst右子树删除key后的bst。否则; *4、若t->item == key: * 1.若其左右子树为NULL,返回NULL,即对其父节点赋值为NULL * 2.若其左子树不为NULL,则在其左子树中找到最大节点p, 将p->item赋值给当前节点,还须要在其左子树中删除p->item, 3.若其右子树不为NULL,则在其左子树中找到最小节点p, 将p->item赋值给当前节点,还须要在其右子树中删除p->item, * *@param t 要插入的 bst *@param key 要插入的值 *@returns 插入后的bst */ link bstDelete(link t, TElemType key) { if (t == NULL) return NULL; if (t->item > key) t->lchild = bstDelete(t->lchild, key); else if (t->item < key) t->rchild = bstDelete(t->rchild, key); else { link p; if (t->lchild == NULL && t->rchild == NULL) { free_node(t); t = NULL; } else if (t->lchild){ for (p = t->lchild; p->rchild; p = p->rchild); t->item = p->item; t->lchild = bstDelete(t->lchild, t->item); } else { for (p = t->rchild; p->lchild; p = p->lchild); t->item = p->item; t->rchild = bstDelete(t->rchild, t->item); } } return t; }測试程序
/* main.c */ #include <stdio.h> #include <time.h> #include "binarytree.h" #define RANGE 50 #define N 15 void print_item(link p) { printf("%d\t", p->item); } void testBst() { int i; link root = NULL; srand(time(NULL)); for (i=0; i<N; i++) root = bstInsert(root, rand()%RANGE); printf("\\tree"); pprint(root); printf("\n"); TElemType key = rand() % RANGE; if (bstSearch(root, key)) { bstDelete(root, key); printf("\n%d\n", key); printf("\\tree"); pprint(root); printf("\n"); } } void testInitByList() { TElemType pre_seq[] = { 4, 2, 1, 3, 6, 5, 7 }; TElemType in_seq[] = { 1, 2, 3, 4, 5, 6, 7 }; link root = init(pre_seq, in_seq, 7); printf("\\tree"); pprint(root); printf("\n"); pre_order(root, print_item); putchar('\n'); in_order(root, print_item); putchar('\n'); post_order(root, print_item); putchar('\n'); printf("count=%d depth=%d\n", count(root), depth(root)); destroy(root); printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } int main() { //testInitByList(); testBst(); return 0; }
相应的Makefie
#if you want to use recursive func,please make recu=y ifeq (y, $(recu)) CFLAGS += -DRECU endif ifeq (y, $(debug)) CFLAGS += -g endif all: gcc $(CFLAGS) main.c binarytree.c binarytree.h -o tree clean: $(RM) tree
编译測试
在这里遍历二叉树仅仅写了递归函数在编译的时候用一下命令
make recu=y debug=y执行结构例如以下:
\tree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23(22()())(29()())))())(41()()))) 22 \tree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23()(29()())))())(41()())))好了接下来就是用工具tree。把这些字符串图形化
echo "\tree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23(22()())(29()())))())(41()())))" | tree -b2怎么样这个效果。
把b2改成b6
版权声明:本文博主原创文章,转载请注明出处