某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树是一种近似平衡的二叉查找树,从2-3树或2-3-4树衍生而来.通过对二叉树节点进行染色,染色为红或黑节点,来模仿2-3树或2-3-4树的3节点和4节点,从而让树的高度减小.2-3-4树对照实现的红黑树是普通的红黑树,而2-3树对照实现的红黑树是一种变种,称为左倾红黑树,其更容易实现. 使用平衡树数据…
哈希表:散列查找 一.线性查找 我们要通过一个键key来查找相应的值value.有一种最简单的方式,就是将键值对存放在链表里,然后遍历链表来查找是否存在key,存在则更新键对应的值,不存在则将键值对链接到链表上. 这种链表查找,最坏的时间复杂度为:O(n),因为可能遍历到链表最后也没找到. 二.散列查找 有一种算法叫散列查找,也称哈希查找,是一种空间换时间的查找算法,依赖的数据结构称为哈希表或散列表:HashTable. Hash: 翻译为散列,哈希,主要指压缩映射,它将一个比较大的域空间映射到…
二叉查找树 二叉查找树,又叫二叉排序树,二叉搜索树,是一种有特定规则的二叉树,定义如下: 它是一颗二叉树,或者是空树. 左子树所有节点的值都小于它的根节点,右子树所有节点的值都大于它的根节点. 左右子树也是一颗二叉查找树. 二叉查找树的特点是,一直往左儿子往下找左儿子,可以找到最小的元素,一直往右儿子找右儿子,可以找到最大的元素. 看起来,我们可以用它来实现元素排序,可是我们却使用了二叉堆来实现了堆排序,因为二叉查找树不保证是一个平衡的二叉树,最坏情况下二叉查找树会退化成一个链表,也就是所有节点…
AVL树 二叉查找树的树高度影响了查找的效率,需要尽量减小树的高度,AVL树正是这样的树. 一.AVL树介绍 AVL树是一棵严格自平衡的二叉查找树,1962年,发明者Adelson-Velsky和Landis发表了论文,以两个作者的名字命名了该数据结构,这是较早发明的平衡二叉树. 定义如下: 首先它是一棵二叉查找树. 任意一个节点的左右子树最大高度差为1. 由于树特征定义,我们可以计算出其高度h的上界h<=1.44log(n),也就是最坏情况下,树的高度约等于1.44log(n). 假设高度h的…
文章首发于 阅读更友好的GitBook. 2-3-4树和普通红黑树 某些教程不区分普通红黑树和左倾红黑树的区别,直接将左倾红黑树拿来教学,并且称其为红黑树,因为左倾红黑树与普通的红黑树相比,实现起来较为简单,容易教学.在这里,我们区分开左倾红黑树和普通红黑树. 红黑树是一种近似平衡的二叉查找树,从2-3树或2-3-4树衍生而来.通过对二叉树节点进行染色,染色为红或黑节点,来模仿2-3树或2-3-4树的3节点和4节点,从而让树的高度减小.2-3-4树对照实现的红黑树是普通的红黑树,而2-3树对照实…
快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:ACM = Association for Computing Machinery,国际计算机学会,世界性的计算机从业员专业组织,创立于1947年,是世界上第一个科学性及教育性计算机学会. 快速排序是对冒泡排序的一种改进,也属于交换类的排序算法. 一.算法介绍 快速排序通过一趟排序将要排序的数据分割成…
排序算法 人类的发展中,我们学会了计数,比如知道小明今天打猎的兔子的数量是多少.另外一方面,我们也需要判断,今天哪个人打猎打得多,我们需要比较. 所以,排序这个很自然的需求就出来了.比如小明打了5只兔子,小王打了8只,还有部落其他一百多个人也打了.我们要论功行赏,谁打得多,谁就奖赏大一点. 如何排序呢,怎么在最快的时间内,找到打兔子最多的人呢,这是一个很朴素的问题. 经过很多年的研究,出现了很多的排序算法,有快的有慢的.比如: 插入类排序有:直接插入排序和希尔排序 选择类排序有:直接选择排序和堆…
冒泡排序 冒泡排序是大多数人学的第一种排序算法,在面试中,也是问的最多的一种,有时候还要求手写排序代码,因为比较简单. 冒泡排序属于交换类的排序算法. 一.算法介绍 现在有一堆乱序的数,比如:5 9 1 6 8 14 6 49 25 4 6 3. 第一轮迭代:从第一个数开始,依次比较相邻的两个数,如果前面一个数比后面一个数大,那么交换位置,直到处理到最后一个数,最后的这个数是最大的. 第二轮迭代:因为最后一个数已经是最大了,现在重复第一轮迭代的操作,但是只处理到倒数第二个数. 第三轮迭代:因为最…
选择排序 选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次.虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟糕. 选择排序属于选择类排序算法. 我打扑克牌的时候,会习惯性地从左到右扫描,然后将最小的牌放在最左边,然后从第二张牌开始继续从左到右扫描第二小的牌,放在最小的牌右边,以此反复.选择排序和我玩扑克时的排序特别相似. 一.算法介绍 现在有一堆乱序的数,比如:5 9 1 6 8 14 6 49 25 4…
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑克时习惯从第二张牌开始,和第一张牌比较,第二张牌如果比第一张牌小那么插入到第一张牌前面,这样前两张牌都排好序了,接着从第三张牌开始,将它插入到已排好序的前两张牌里,形成三张排好序的牌,后面第四张牌继续插入到前面已排好序的三张牌里,直至排序完. 一.算法介绍 举个简单例子,插入排序一个 4 个元素的数…
希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机学会月刊发布了一个排序算法,从此名为希尔排序的算法诞生了. 注:ACM = Association for Computing Machinery,国际计算机学会,世界性的计算机从业员专业组织,创立于1947年,是世界上第一个科学性及教育性计算机学会. 希尔排序是直接插入排序的改进版本.因为直接插入…
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_Neumann在1945年发明,被用在了EDVAC(一台美国早期电子计算机),足足用墨水写了 23 页的排序程序.注:冯·诺依曼(John von Neumann,1903年12月28日-1957年2月8日),美籍匈牙利数学家.计算机科学家.物理学家,是20世纪最重要的数学家之一. 一.算法介绍 我…
优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉堆数据结构的可用性.同年,美国籍计算机科学家R. W. Floyd在其树排序研究的基础上,发布了一个改进的更好的原地排序的堆排序版本. 堆排序属于选择类排序算法. 一.优先队列 优先队列是一种能完成以下任务的队列:插入一个数值,取出最小或最大的数值(获取数值,并且删除). 优先队列可以用二叉树来实现…
1.红黑树和自平衡二叉(查找)树区别 1.红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单. 2.平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知. AVL树是最早出现的自平衡二叉(查找)树 红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能.红黑树和AVL树的区别在于它使用颜色来标识结点的高度,它…
0.目录 1.KMP 子串查找算法 2.KMP 算法的应用 3.小结 1.KMP 子串查找算法 问题: 如何在目标字符串S中,查找是否存在子串P? 朴素解法: 朴素解法的一个优化线索: 示例: 伟大的发现: 匹配失败时的右移位数与子串本身相关,与目标串无关 移动位数 = 已匹配的字符数 - 对应的部分匹配值 任意子串都存在一个唯一的部分匹配表 部分匹配表示例: 问题: 部分匹配表是怎么得到的? 前缀 除了最后一个字符以外,一个字符串的全部头部组合 后缀 除了第一个字符以外,一个字符串的全部尾部组…
字符串查找即为特征查找: 特征即位hash: 1.将待查找的字符串hash: 2.在容器字符串中找头字符匹配的字符串,并进行hash: 3.比较hash的结果:相同即位匹配: hash算法的设计为其中的重点.…
——参考自<算法图解> 我们假设需要查找的数组是有序的(从大到小或者从小到大),如果无序,可以在第四行后插入一句 my_list.sort() 完整代码如下 def binary_search(my_list, item): # low和high用于跟踪要在其中查找到的列表的部分 low = 0 high = len(my_list)-1 while low <= high: mid = (low+high)//2 # 地板除,保证mid为整数 guess = my_list[mid]…
day10 python       1.冒泡算法         冒泡排序,把列表竖起来看,就像一个个气泡往上去(时间复杂度大) lst = [12,3,3,2424,14,3567,534,324,324,23,4,23,42,4324]   for num in range(len(lst)):     for i in range(len(lst)-1):         if lst[i] > lst[i+1]:             lst[i], lst[i+1] = lst[i…
数据结构和算法在计算机科学里,有非常重要的地位.此系列文章尝试使用 Golang 编程语言来实现各种数据结构和算法,并且适当进行算法分析. 我们会先简单学习一下Golang,然后进入计算机程序世界的第一个大门. 简单入门Golang 我们只学Golang语言的一个子集,足以开展接下来数据结构和算法的实现即可. 一.前言 Golang语言是谷歌Google公司在2007年启动,并在2009年正式发布并开源的高级编程语言.开源地址:https://github.com/golang/go,官网地址:…
包.变量和函数 一.举个例子 现在我们来建立一个完整的程序main.go: // Golang程序入口的包名必须为 main package main // import "golang" // 导入其他地方的包,包通过 go mod 机制寻找 import ( "fmt" "golang/diy" ) // init函数在main函数之前执行 func init() { // 声明并初始化三个值 var i, j, k = 1, 2, 3 //…
流程控制语句 计算机编程语言中,流程控制语句很重要,可以让机器知道什么时候做什么事,做几次.主要有条件和循环语句. Golang只有一种循环:for,只有一种判断:if,还有一种特殊的switch条件选择语句. 一.条件语句 举个例子: // 判断语句 if a > 0 { fmt.Println("a>0") } else { fmt.Println("a<=0") } 当a > 0时打印a>0,否则打印a<=0.其中条件a &…
结构体和方法 一.值,指针和引用 我们现在有一段程序: package main import "fmt" func main() { // a,b 是一个值 a := 5 b := 6 fmt.Println("a的值:", a) // 指针变量 c 存储的是变量 a 的内存地址 c := &a fmt.Println("a的内存地址:", c) // 指针变量不允许直接赋值,需要使用 * 获取引用 //c = 4 // 将指针变量 c…
接口 在Golang世界中,有一种叫interface的东西,很是神奇. 一.数据类型 interface{} 如果你事前并不知道变量是哪种数据类型,不知道它是整数还是字符串,但是你还是想要使用它. Golang就产生了名为interface{}的数据类型,表示并不知道它是什么类型.举例子: package main import ( "fmt" "reflect" ) func print(i interface{}) { fmt.Println(i) } fun…
并发.协程和信道 Golang语言提供了go关键字,以及名为chan的数据类型,以及一些标准库的并发锁等,我们将会简单介绍一下并发的一些概念,然后学习这些Golang特征知识. 一.并发介绍 我们写程序时,可能会读取一个几千兆的日志,读磁盘可能需要读几十秒钟,我们不可能一直等他,因为虽然磁盘IO繁忙,但是处理器CPU很空闲,我们可以并发地开另一条路去处理其他逻辑. 在操作系统层面,出现了多进程和多线程的概念.一个处理器会在一个时间片里比如20纳秒执行一个进程,当时间片用完了或者发生了中断比如进程…
使用标准库 一.避免重复造轮子 官方提供了很多库给我们用,是封装好的轮子,比如包fmt,我们多次使用它来打印数据. 我们可以查看到其里面的实现: package fmt func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) } func Printf(format string, a ...interface{}) (n int, err error) { return Fprin…
基础知识 学习数据结构和算法.我们要知道一些基础的知识. 一.什么是算法 算法(英文algorithm)这个词在中文里面博大精深,表示算账的方法,也可以表示运筹帷幄的计谋等.在计算机科技里,它表示什么呢? 计算机,顾名思义是用来计算的机器.算法在计算机科学中可以描述为:计算机接收一个输入指令,然后进行一个过程处理,最后输出计算的结果. 这种输入-过程处理-输出,用人类的行为模式,很容易理解,比如妈妈让小明去打酱油,打酱油的命令是输入,小明发现小区周边有5家店有酱油出售,娟娟超市是离家最近的,而子…
分治法和递归 在计算机科学中,分治法是一种很重要的算法. 字面上的解释是分而治之,就是把一个复杂的问题分成两个或更多的相同或相似的子问题. 直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 分治法一般使用递归来求问题的解. 一.递归 递归就是不断地调用函数本身. 比如我们求阶乘1 * 2 * 3 * 4 * 5 *...* N: package main import "fmt" func Rescuvie(n int) int { if n == 0 { return…
算法复杂度及渐进符号 一.算法复杂度 首先每个程序运行过程中,都要占用一定的计算机资源,比如内存,磁盘等,这些是空间,计算过程中需要判断,循环执行某些逻辑,周而反复,这些是时间. 那么一个算法有多好,多快,怎么衡量一个算法的好坏?所以,计算机科学在算法分析过程中,提出了算法复杂度理论,这套理论可以量化算法的效率,以此作为标准,方便我们能衡量到底选择哪一种算法. 复杂度有两个维度:时间和空间. 我们说,一个实现了某算法的程序: 如果计算的速度越快,那么这个算法时间复杂度越低. 如果占用的计算资源越…
算法复杂度主方法 有时候,我们要评估一个算法的复杂度,但是算法被分散为几个递归的子问题,这样评估起来很难,有一个数学公式可以很快地评估出来. 一.复杂度主方法 主方法,也可以叫主定理.对于那些用分治法,有递推关系式的算法,可以很快求出其复杂度. 定义如下: 如果对证明感兴趣的可以翻阅书籍:<算法导论>.如果觉得太难思考,可以跳过该节. 由于主定理的公式十分复杂,所以这里有一种比较简化的版本来计算: 二.举例 二分搜索,每次问题规模减半,只查一个数,递推过程之外的查找复杂度为O(1),递推运算时…
常见数据结构及算法 数据结构主要用来组织数据,也作为数据的容器,载体. 各种各样的算法,都需要使用一定的数据结构来组织数据. 常见的典型数据结构有: 链表 栈和队列 树 图 上述可以延伸出各种各样的术语和结构,如列表,集合,哈希表,堆,优先队列,二叉树,红黑树,B+树以及各种变种等. 我们区别开数据结构和算法,是因为算法是更高层次的一种智慧结晶,目的就是为了解决问题,基本的算法分类有: 排序算法 查找算法 图相关的算法 其他的算法 计算机科学作为数学的一个分支,大部分的数学知识都是离散数学.我们…