算法与数据结构

数据结构与算法之美学习笔记:第十四讲

我只是一个虾纸丫 提交于 2019-12-05 00:30:27
一、课前问题 几乎所有的编程语言都会提供排序函数,比如C语言中qsort(),C++ STL中的sort()、stable_sort(),还有Java语言中的Collections.sort()。 在平时的开发中,我们也都是直接使用这些现成的函数来实现业务逻辑中的排序功能。那你知道这些排序函数是如何实现的吗?底层都利用了哪种排序算法呢? 基于这些问题,今天我们就来看排序这部分的最后一块内容:如何实现一个通用的、高性能的排序函数? 二、如何选择合适的排序算法 如果要实现一个通用的、高效率的排序函数,我们应该选择哪种排序算法?我们先回顾一下前面讲过的一种排序算法。 我们前面讲过,线性排序算法的时间复杂度比较低,适用场景比较特殊。所以如果要写一个通用的排序函数,不能选择线性排序算法。 如果对小规模数据进行排序,可以选择时间复杂度是O(n )的算法; 如果对大规模数据进⾏排序,时间复杂度是O(nlogn)的算法更加高效。 所以,为了兼顾任意规模数据的排序,一般都会首选时间复杂度是O(nlogn)的排序算法来实现排序函数。 时间复杂度是O(nlogn)的排序算法不止一个,我们已经讲过的有归并排序、快速排序,后面讲堆的时候我们还会讲到堆排序。堆排序和快速排序都有比较多的应用,比如Java语言采用堆排序实现排序函数,C语言使用快速排序实现排序函数。 不知道你有没有发现,

20182301 2019-2020-1 《数据结构与面向对象程序设计》第9周学习总结

Deadly 提交于 2019-12-05 00:26:35
20182301 2019-2020-1 《数据结构与面向对象程序设计》第9周学习总结 教材学习内容总结 第十六章 树的定义 根节点:唯一 节点的度:节点拥有的子树数。度为0:称为终端节点或叶节点 树的度:树内各节点的度的最大值 内部节点:除根节点外的节点 孩子(child):节点的子树的根 称为该节点的孩子,反过来,称为双亲(parent) 兄弟(sibling):同一双亲的孩子之间的关系 节点的祖先:从根到该节点所经分支上的全部节点 节点层次:根为第一层,根的孩子为第二层 树的深度(Depth):树中节点的最大层次 森林(Forest):是m(m>0)棵互不相交的树的集合 树的分类 满二叉树 如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。 如果一个二叉树的层数为K,且结点总数是(2^k) -1,则它就是满二叉树。 完全二叉树 它是由满二叉树而引出来的。 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边, 线索二叉树 n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域(就是用于指向左右孩子的域)。 利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。 加上线索的二叉树称为线索二叉树。 哈夫曼树(霍夫曼树)又称为最优树

数据结构与算法之美学习笔记:第十五讲

浪子不回头ぞ 提交于 2019-12-05 00:26:19
一、课前问题 今天我们讲一种针对有序数据集合的查找算法:二分查找(Binary Search)算法,也叫折半查找算法。二分查找的思想非常简单,很多非计算机专业的同学很容易就能理解, 但是看似越简单的东西往往越难掌握好,想要灵活应用就更加困难。老规矩,我们还是来看一道思考题。 假设我们有1000万个整数数据,每个数据占8个字节, 如何设计数据结构和算法,快速判断某个整数是否出现在这1000万数据中? 我们希望这个功能不要占用太多的内存空间, 最多不要超过100MB,你会怎么做呢?带着这个问题,让我们进行今天的内容吧! 二、无处不在的二分思想 二分查找是一种非常简单易懂的快速查找算法,生活中到处可见。比如说,我们现在来做一个猜字游戏。我随机写一个0到99之间的数字,然后你来猜我写的是什么。猜的过程中, 你每猜一次,我就会告诉你猜的对了还是错了,直到猜中为止。你来想想, 如何快速猜中我写的数字呢? 假设我写的数字是23,你可以按照下面的步骤来试一试。(如果猜测范围的数字有偶数个,中间数有两个,就选择较小的那个。) 7次就猜出来了,是不是很快?这个例子用的就是二分思想, 按照这个思想,即便我让你猜的是0到999的数字,最多也只要10次就能猜中。不信的话,你可以试一试。 这是一个生活中的例子,我们现在回到实际的开发场景中。 假设有1000条订单数据,已经按照订单金额从小到大排序,

数据结构与算法之美学习笔记:第十三讲

大城市里の小女人 提交于 2019-12-05 00:24:45
一、课前问题 上两节中,我带你着重分析了几种常用排序算法的原理、时间复杂度、空间复杂度、稳定性等。今天,我会讲三种时间复杂度是O(n)的排序算法:桶排序、计数排序、基数排序。 因为这些排序算法的时间复杂度是线性的,所以我们把这类排序算法叫作线性排序(Linear sort)。之所以能做到线性的时间复杂度,主要原因是,这三个算法是非基于比较的排序算法, 都不涉及元素之间的比较操作。 这几种排序算法理解起来都不难,时间、空间复杂度分析起来也很简单,但是对要排序的数据要求很苛刻,所以我们今天 学习重点的是掌握这些排序算法的适用场景 。 按照惯例,我先给你出一道思考题: 如何根据年龄给100万用户排序? 你可能会说,我用上一节课讲的归并、快排就可以搞定啊!是的,它们也可以完成功能,但是时间复杂度最低也是O(nlogn)。有没有更快的排序方法呢?让我们一起进入今天的内容! 二、桶排序(Bucket sort) 1、桶排序的核心思想 首先,我们来看桶排序。桶排序,顾名思义,会用到“桶”,核心思想是将要排序的数据分到一个有序的桶里,每个桶里的数据 再单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。 桶排序的时间复杂度为什么是O(n)呢?我们一块儿来分析一下。 如果要排序的数据有n个,我们把它们均匀地划分到m个桶内,每个桶里就有k=n/m个元素。

数据结构与算法之美学习笔记:第十七讲

£可爱£侵袭症+ 提交于 2019-12-05 00:22:11
一、课前思考 两节我们讲了二分查找算法。当时我讲到,因为二分查找底层依赖的是数组随机访问的特性,所以只能用数组来实现。如果数据存储在链表中,就真的没法用二分查找算法了吗? 实际上,我们只需要对链表稍加改造,就可以支持类似“二分”的查找算法。我们把改造之后的数据结构叫作跳表(Skiplist),也就是今天要讲的内容。 跳表这种数据结构对你来说,可能会比较陌生,因为一般的数据结构和算法书籍里都不怎么会讲。但是它确实是一种各方面性能都比较优秀的动态数据结构,可以支持快速的插入、删除、查找操作, 写起来也不复杂,甚至可以替代红黑树(Red-blacktree)。 Redis中的有序集合(Sorted Set)就是⽤跳表来实现的。如果你有一定基础,应该知道红黑树也可以实现快速的插入、删除和查找操作。 那Redis为什么会选择用跳表来实现有序集合呢? 为什么不用红黑树呢?学完今天的内容,你就知道答案了。 二、如何理解跳表 1、单链表 2、怎么提高查询效率 1、18个节点一级索引 2、18个节点二级索引 3、64个节点建立五级索引 3、当链表的⻓度n⽐较⼤时 三、用跳表查询到底有多快 1、如果链表⾥有n个结点,会有多少级索引? 2、复杂度推算过程 3、M值为什么是3 4、基于单链表实现二分查找 四、跳表是不是很浪费内存 1、索引节点数是一个等比数列 2、通过等⽐数列求和公式 3、实际上

数据结构与算法之美学习笔记:第二十三讲

大憨熊 提交于 2019-12-05 00:21:43
一、课前思考 前面我们讲的都是线性表结构,栈、队列等等。今天我们讲一种非线性表结构,树。树这种数据结构牛逼线性表的数据结构要复杂得多,内容也比较多,所以我会分四节来讲解。 我反复强调过,带着问题学习,是最有效的学习方式之一,所以在正式的内容开始之前,我还是给你出几道思考题: 二叉树有哪几种存储方式?什么样的二叉树适合用数组来存储? 带着这些问题,我们就来学习今天的内容,树! 二、树 1、一些节本概念 图中画了几棵“树”。你来看看,这些“树”都有什么特征? 你有没有发现,“树”这种数据结构真的很像我们现实生活中的“树”,这里面每个元素我们叫作“节点”;用来连线相邻节点之间的关系,我们叫作“父子关系”。 比如下面这幅图: A节点就是B节点的 父节点 ,B节点是A节点的 子节点 。 B、C、D这三个节点的父节点是同一个节点,所以它们之间互称为 兄弟节点 。 我们把没有父节点的节点叫作 根节点 ,也就是图中的节点E。 我们把没有子节点的节点叫作叶子节点或者 叶节点 ,比如图中的G、H、I、J、K、L都是叶子节点。 2、高度深度和层 除此之外,关于“树”,还有三个比较相似的概念:高度(Height)、深度(Depth)、层(Level)。它们的定义是这样的: 这三个概念的定义比较容易混淆,描述起来也比较空洞。我举个例子说明一下,你一看应该就能明白。 记这住个概念,我还有一个小窍们,就是类比

java-数据结构-大顶堆和小顶堆

邮差的信 提交于 2019-12-04 22:25:37
java-数据结构-大顶堆和小顶堆 概念 1)堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。 2)堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆, 注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系。 3)每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆 大顶堆举例说明 大顶堆特点: arr[i] >= arr[2*i+1] && arr[i] >= arr[2*i+2] // i 对应第几个节点,i从0开始编号 小顶堆举例说明 小顶堆: arr[i] <= arr[2*i+1] && arr[i] <= arr[2*i+2] // i 对应第几个节点,i从0开始编号 一般升序采用大顶堆,降序采用小顶堆 堆排序基本思想 堆排序的基本思想是: 1)将待排序序列构造成一个大顶堆 2)此时,整个序列的最大值就是堆顶的根节点。 3)将其与末尾元素进行交换,此时末尾就为最大值。 4)然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。 package com . tree ; import java . text . SimpleDateFormat ; import java . util .

【从今天开始好好学数据结构02】栈与队列

自古美人都是妖i 提交于 2019-12-04 21:18:54
目录 1、理解栈与队列 2、用代码谈谈栈 3、用代码谈谈队列 我们今天主要来谈谈“栈”以及队列这两种数据结构。 回顾一下上一章中 【数据结构01】数组 中,在数组中只要知道数据的下标,便可通过顺序搜索很快查询到数据,可以根据下标不同自由查找,然而今天要讲的“栈”以及队列这两种数据结构访问是受限制的,只允许在一端读取、插入和删除数据,这时候对它存在的意义产生了很大的疑惑。因为会觉得,相比数组和链表,栈带给我的只有限制,并没有任何优势。那我直接使用数组或者链表不就好了吗?为什么还要用这个“操作受限”的“栈”呢?事实上,从功能上来说,数组或链表确实可以替代栈,但你要知道,特定的数据结构是对特定场景的抽象,而且,数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。 @ 1、理解栈与队列 首先,如何理解“栈”?用现实一个通俗贴切的例子,我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们是从上往下一个一个地依次取,不能从中间任意抽出, 先进后出 ,这就是典型的“ 栈 ”结构 ,当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,我们就应该首选“栈”这种数据结构。 其次如何理解队列?同样用现实一个通俗贴切的例子,平时在校的时候饭堂吃饭都是排队,而且不能插队,先进先出,这就是典型的队列结构 2、用代码谈谈栈 实际上

8大数据结构

…衆ロ難τιáo~ 提交于 2019-12-04 20:58:37
数据结构分类 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成 。 常用的数据结构有:数组,栈,链表,队列,树,图,堆,散列表等,如图所示: 每一种数据结构都有着独特的数据存储方式,下面为大家介绍它们的结构和优缺点。 1 、数组 数组是可以再内存中连续存储多个元素的结构,在内存中的分配也是连续的,数组中的元素通过数组下标进行访问,数组下标从 0 开始。例如下面这段代码就是将数组的第一个元素赋值为 1 。 int[] data = new int[100]; data[0] = 1; 优点: 1 、按照索引查询元素速度快 2 、按照索引遍历数组方便 缺点: 1 、数组的大小固定后就无法扩容了 2 、数组只能存储一种类型的数据 3 、添加,删除的操作慢,因为要移动其他的元素。 适用场景: 频繁查询,对存储空间要求不大,很少增加和删除的情况。 2 、栈 栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。 栈的特点是:先进后出,或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。 栈的结构就像一个集装箱,越先放进去的东西越晚才能拿出来,所以,栈常应用于实现递归功能方面的场景,例如斐波那契数列。 3 、队列 队列与栈一样,也是一种线性表,不同的是,队列可以在一端添加元素,在另一端取出元素,也就是:先进先出

数据结构与算法(位运算)

有些话、适合烂在心里 提交于 2019-12-04 20:43:18
位运算 内存中的数据,最终的存储方式都是二进制,位运算就是对整数在内存的二进制位进行操作。 按位与 & 两个整数进行按位与运算,相同二进制位的数字如果都是是,则结果为1,有一个为0,则结果为0 下面是 3 & 7 的计算过程 二进制 整数 0 1 1 3 1 1 1 7 0 1 1 3(结果) 3 & 7 = 3 按位或 | 两个整数进行按位或运算,相同二进制位的数字如果有一个为1,则结果为1,都为0,则结果为0 下面是 5 | 8 的计算过程 二进制 整数 0 1 0 1 5 1 0 0 0 8 1 1 0 1 13(结果) 5 | 8 = 13 左移 << 二进制向左移动n位,在后面添加n个0 下面的 3 << 1 的计算过程 二进制 整数 1 1 3 1 1 0 6 3<<1 = 6 练习:一组数,内容为 3,9,19,20 ,请用一个整数来表示这四个数 var value = 0 value = value | 1<<3 value = value | 1<<9 value = value | 1<<19 value = value | 1<<20 console.log(value) 程序输出结果为:1573384 bitmap 新的实现方式 经过前面一系列的分析和位运算学习,现在我们要重新设计一个类,实现 addMember 和 isExist 方法,用更快的速度