• 二二叉搜索树学习


    写在前面的话

    最近接到几所大学的学生毕业后无法登录华为签订百度,我去学习:操作系统、数据结构与算法、利器。想想自己工作2.5年月薪还不到10K,过着苦逼的码农生活,而他们一出校门就是大放光芒(最起码进入的公司就让人认为牛逼哄哄的).本人痛定思痛,决定下大功夫学习一下数据结构与算法,我想这应该是根本吧.
    之前也看过数据结构,可是一看到那乱七八糟的关系,就认为还是研究一下别的东西,结果就是好多东西都是浅尝辄止,知子皮毛.
    本人仅仅贴出学习过程中的代码,以及一些发杂算法函数的具体凝视,还有就是学习过程中遇到过的好的解说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、关联数组等。

    * *搜索,插入,删除的复杂度等于树高,期望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
    /* 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	", 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("
    ");
    
    	TElemType key = rand() % RANGE;
    	if (bstSearch(root, key)) {
    		bstDelete(root, key);
    		printf("
    %d
    ", key);
    
    		printf("\tree");
    		pprint(root);
    		printf("
    ");
    	}
    }
    
    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("
    ");
    
    	pre_order(root, print_item);
    	putchar('
    ');
    	in_order(root, print_item);
    	putchar('
    ');
    	post_order(root, print_item);
    	putchar('
    ');
    	printf("count=%d depth=%d
    ", count(root), depth(root));
    	destroy(root);
    	printf("+++++++++++++++++++++++++++++++++++++++++++++++++++
    
    ");
    }
    
    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
    执行结构例如以下:
    	ree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23(22()())(29()())))())(41()())))
    
    22
    	ree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23()(29()())))())(41()())))
    好了接下来就是用工具tree。把这些字符串图形化
    echo "	ree(15(6(0()())(7()(14(11(8()())())())))(41(36(18(16()())(23(22()())(29()())))())(41()())))" | tree -b2
    怎么样这个效果。


    把b2改成b6

    版权声明:本文博主原创文章,转载请注明出处

  • 相关阅读:
    CMake 从文件路径中提取文件名
    std::multimap 按照key遍历---
    Windows / Linux 一件编译zlib库
    C++ 11 可变模板参数的两种展开方式
    cmake 生成VS项目文件夹
    C++ 利用文件流复制文件
    利用 getsockname 和 getpeername 来获取某一个链接的本地地址和远端地址
    Windows 用VS编译libevent源码
    揭示同步块索引(上):从lock开始
    C手写一个多线程,供java调用
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4817036.html
Copyright © 2020-2023  润新知