二叉搜索树

 前言:    先立flag吧,18年每天一个算法或数据结构知识点的学习与总结!每周5个,大约会有50个吧,感觉基础的数据结构和算法都应该掌握了!但不能每天都写博客,时间有限,每周一篇或两篇进行分享,年底进行检验结果,加油!   这次要介绍的是二叉搜索树,从名字也能看出它的实现和作用了,实现是以二叉树为基础来实现的,作用是进行数据查找。   一、二分查找   二分查找应该应熟悉了吧?要在顺序储存结构中进行查找,跟最中间的数据进行比较,小的话去前半部分进行查找,否则,去后半部分去查找,其实,可以用迭代和递归分别来实现二分查找。   1、迭代法     首先,用迭代法来实现,代码如下: 复制代码 // 二分查找法,在有序数组arr中,查找target // 如果找到target,返回相应的索引index // 如果没有找到target,返回-1 template int binarySearch(T arr[], int n, T target){ // 在arr[l...r]之中查找target int l = 0, r = n-1; while( l <= r ){ //int mid = (l + r)/2; int mid = l + (r-l)/2; if( arr[mid] == target ) return mid; if( arr[mid] > target ) r = mid - 1; else l = mid + 1; } return -1; } 复制代码   需要注意的一点是:int mid = (l + r)/2;我注释的这个求mid会有一个bug,当l和r达到int的最大值时,会出现越界的问题。这也是算法的魅力,需要注意很多细节并有很多地方需要优化!学无止境!   2、递归法   用递归法实现,代码如下: 复制代码 // 用递归的方式写二分查找法 template int __binarySearch2(T arr[], int l, int r, T target){ if( l > r ) return -1; int mid = (l+r)/2; if( arr[mid] == target ) return mid; else if( arr[mid] > target ) return __binarySearch2(arr, 0, mid-1, target); else return __binarySearch2(arr, mid+1, r, target); } 复制代码   用递归最重要的一点就是:要有结束条件   3、main函数测试两种方法   写一个main函数,进行简单的测试,数据量用的比较大,PS:用一个算法进行一下优化,一看数据量就几百,根本没必要优化,数据量不过万,谈算法意义并不大! main函数主要对两种算法进行时间对比: View Code   运行结果如下:     会发现递归运行时间长,因为递归会反复调用,会耗时的。   二、二叉搜索树   1、介绍   什么是二叉搜索树呢?   首先,它是一颗二叉树: (1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值; (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值; (3)左、右子树也分别为二叉排序树;   如下图就是二叉搜索树:      2、构建一个BST类   先建一个BST类用于存放二叉搜索树,还包括一些构造函数、插入和查找等,代码如下: View Code   3、插入节点   首先,它是二叉树,都具有的性质是递归,所以用递归相对比较简单,画一张图如下供参考:      假如,先插入8,跟根节点12比较,比它小去左子树,跟节点5比较,比它大去右子树;再例如,插入13,跟根节点12比较,比它大去右子树;代码如下: 复制代码 // 向以node为根的二叉搜索树中,插入节点(key, value) // 返回插入新节点后的二叉搜索树的根 Node* insert(Node *node, Key key, Value value) { if (node == NULL) { count++; return new Node(key, value); } if (key == node->key) node->value = value; else if (key < node->key) node->left = insert(node->left, key, value); else // key > node->key node->right = insert(node->right, key, value); return node; } 复制代码   4、查找节点   跟插入的思想很像,也是不断比较,用递归的思想去查找,代码如下: 复制代码 // 在以node为根的二叉搜索树中查找key所对应的value Value* search(Node* node, Key key) { if (node == NULL) return NULL; if (key == node->key) return &(node->value); else if (key < node->key) return search(node->left, key); else // key > node->key return search(node->right, key); } 复制代码   5、三种遍历方法   三种方法分别是:先序遍历、中序遍历和后序遍历。画图讲解一下吧,如下图:  PS:依旧是全网最丑图,不接受反驳!      三种遍历的本质:访问路径一样,访问顺序不一样。   先序遍历:根左右,先访问根节点、再左节点、其次右节点   中序遍历:左根右,先访问左节点、再根节点、其次右节点   后序遍历:左右根,先访问左节点、再右节点、其次根节点   用上面的图解释这句话,那条红线就是访问路径,三种遍历方式都是这条访问路径;用节点旁边的三个红点来表示访问和顺序,这么说,可能还是懵。   拿先序来举个例子吧:访问路径一样,都从根节点12出发,遇到“先序红点”,直接输出12,然后是5,最后的先序结果上图下面的结果。   (1)先序遍历   先序遍历程序如下: 复制代码 // 对以node为根的二叉搜索树进行先序遍历 void preOrder(Node* node) { if (node != NULL) { cout << node->key << endl; preOrder(node->left); preOrder(node->right); } } 复制代码   (2)中序遍历   中序遍历程序如下:  复制代码 // 对以node为根的二叉搜索树进行中序遍历 void inOrder(Node* node) { if (node != NULL) { inOrder(node->left); cout << node->key << endl; inOrder(node->right); } } 复制代码   (3)后序遍历   后序遍历程序如下: 复制代码 // 对以node为根的二叉搜索树进行后序遍历 void postOrder(Node* node) { if (node != NULL) { postOrder(node->left); postOrder(node->right); cout << node->key << endl; } } 复制代码   6、总体程序   总体的程序如下,方便调试和使用,程序如下: View Code      总结:      坚持学习与分享!喜欢的帮忙推荐,有问题欢迎随时留言!          作者:柳德维 出处:https://www.cnblogs.com/liudw-0215/ ------------------------------------------- 个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人! 如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢! 万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!https://www.cnblogs.com/liudw-0215/p/9835691.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信