一、算法和数据结构基础
程序 = 数据结构 + 算法
数据结构是计算机存储、组织数据的方式。
数据结构只是静态的描述了数据元素之间的关系,
高效的程序需要在数据结构的基础上设计和选择算法。
算法是为了解决实际问题而设计的。
数据结构是算法需要处理的问题载体。
算法效率的度量:
1.事后统计法
2.事前分析估算
算法的时间复杂度,指最坏时间复杂度;
大O表示法表示算法的时间复杂度,只有常数项记作 1 .
操作数量的估算可以作为时间复杂度的估算。
二、线性表概念
线性表 是零个或多个数据元素的有限序列。
特性:
数据元素之间是有序的。
数据元素个数是有限的。
数据元素类型是相同的。
存储方式:
顺序存储结构
用一段地址【连续的】存储单元依次存储线性表的数据元素。
链式存储结构
用一段地址【非连续的】存储单元存储线性表的数据元素。
三、线性表——顺序存储结构
四、线性表——链式存储结构
-
链式存储
demo Test_LinkList() -
循环链表
最优链表就是:指针域和数据域分开。 取数据时,转换指针类型。
利用循环链表解决约瑟夫问题。
demo Test_CircleLinkList_Josephus_problem() -
双向链表
五、受限线性表——栈(stack)
先进后出
-
栈的顺序存储
demo Test_SeqStack() -
栈的链式存储
demo Test_LinkStack()
六、受限线性表——队列(queue)
先进后出。
First In first out.
- 顺序存储
demo Test_SeqQueue()
七、栈的应用
-
中缀表达式转后缀表达式
后缀表达式就是计算机的计算顺序 eg: 5 + 4 => 5 4 + 中缀表达式符合人的表达方式。 eg:1 + 2 * 3 => 1 2 3 * +
eg:
八、树
存储方式:
九、树——二叉树
-
概念
eg:
-
List item
十、算法——排序
十一、算法——冒泡排序
源码链接:Algorithm_BubbleSort_main()
十二、算法——选择排序
每一次从待排序的数据元素中选出最小(最大)的一个元素,存放在序列的起始位置,
然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
以此类推,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。
源码链接:Algorithm_SelectSort_main()
十三、算法——插入排序
1、将待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列;
2、取出下一个元素,在已经排序的元素序列中从后向前扫描;
3、如果该元素(已排序)大于新元素,将该元素移到下一位置;
4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5、将新元素插入到该位置后;
6、重复步骤2~5。
适合:
1.元素序列基本有序的情况下
基本有序:小的都在左边,大的都在右边
2. 元素个数比较小的时候
源码链接:Algorithm_InsertionSort_main()
十四、算法——希尔排序
希尔排序是特殊的插入排序
时间复杂度
希尔排序的时间复杂度依赖于增量序列的函数,有人在大量的实验后得出的结论:
当n在某个特定的范围后,在最优的情况下,希尔排序的时间复杂度为O(n1.3),在最差的情况下,希尔排序的时间复杂度为:O(n2).
空间复杂度
希尔排序的空间复杂度:O(1).
源码链接:Algorithm_ShellSort_main()
十五、算法——快速排序
1. 首先取出一个key,一般取第一个元素
2. 先从后往前遍历,如果数组中的数据小于了key,那么就将从前往后未比较过的第一个位置即fisrt位置替换为该数据
3. 然后从前往后遍历,如果数组中的数据大于了key,那么就将从后往前的第一个比较过数据位置替换
4. 然后直到左右两边的位置重合,说明key就找到了正确的位置,每次循环就能找到一个数的正确位置
5. 然后将key左右两边的数据分为两组,递归调用自己。
源码链接:Algorithm_QuickSort_main()
十六、算法——归并排序
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分(递归实现)
(2)“合并”——将划分后的序列段两两合并后排序
如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。
这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。
先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。
我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。
每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中,最后将各段中余下的部分直接复制到R2中。
经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。
源码链接:Algorithm_MergeSort_main()
十七、堆排序
最好和最坏的情况时间复杂度都是O(nlogn),空间复杂度O(1)。
堆是一种数据结构,一种叫做【完全二叉树】的数据结构。
堆的分类:
大顶堆:每个节点的值都大于或者等于它的左右子节点的值。
小顶堆:每个节点的值都小于或者等于它的左右子节点的值。
上面大小顶堆的逻辑结构映射到数组中,就是下边这样
9 5 8 2 3 4 7 1
1 3 5 4 2 8 9 7
这个数组arr逻辑上就是一个堆。
从这里我们可以得出以下性质(重点)
对于大顶堆:arr[i] >= arr[2i + 1] && arr[i] >= arr[2i + 2]
对于小顶堆:arr[i] <= arr[2i + 1] && arr[i] <= arr[2i + 2]