(详解数据结构专业网站:http://student.zjzk.cn/course_ware/data_structure/web/main.htm)
注:绝非广告,只是个人觉得该网站讲的很好,参考而已
数据元素相互之间的关系称为结构。
一 四类基本结构:
集合、线性结构、树形结构、图状结构;
(1)集合结构:
除了同属于一种类型外,别无其它关系
(2)线性结构:
元素之间存在一对一关系常见类型有: 数组,链表,队列,栈,它们之间在操作上有所区别.例如:链表可在任意位置插入或删除元素,而队列在队尾插入元素,队头删除元素,栈只能在栈顶进行插 入,删除操作.
(3)树形结构:
元素之间存在一对多关系,常见类型有:树(有许多特例:二叉树、平衡二叉树、查找树等)
(4)图形结构:
元素之间存在多对多关系,图形结构中每个结点的前驱结点数和后续结点多个数可以任意
二 数据结构中排序和查找的算法
(一)排序算法
排序算法是一种基本并且常用的算法。由于实际工作中要处理的数据量巨大,所以对排序算法有很高的速度要求。而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。O方法的定义:
若存在一个常量K和起点n0,使当n>=n0时,有f(n)<=K×g(n),则f(n) = O(g(n))。
我们将按照算法的复杂度,从简单到复杂来分析算法。影响我们算法性能的主要部分是比较和交换,显然,比较和交换次数越多,性能就越差。按照关键字相同的元素在排序前后的相对位置是否改变,排序算法可以分为稳定的和不稳定的。
1、分几大类:
(1)插入排序法(包括直接插入排序、希尔排序)
插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。
直接插入排序法基本思想:
假设待排序的记录存放在数组R[1..n]中。初始时,R[1]自成1个有序区,无序区为R[2..n]。从i=2起直至i=n为止,依次将R[i]插入当前的有序区R[1..i-1]中,生成含n个记录的有序区。
希尔排序基本思想:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插人排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。
(2)交换排序法(包括冒泡法、快速排序)
交换排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。
冒泡排序法基本思想:
将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为R[i].key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。。
(3)选择排序法 (包括直接选择排序和堆排序)
选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。
(4) 归并排序法(归并排序)
归并排序法基本思想:
设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量R1(相当于输出堆)中,待合并完成后将R1复制回R[low..high]中。
(5) 分配排序法(包括基数排序、箱排序)
分配排序的基本思想:
排序过程无须比较关键字,而是通过"分配"和"收集"过程来实现排序.它们的时间复杂度可达到线性阶:O(n)。
2、对排序算法的总结
(1)若n较小(如n≤40),可采用插入排序或选择排序。当记录规模较小时,插入排序较好;反之,因为选择移动的记录数少于插人,应选选择排序为宜。(2)若文件初始状态基本有序(指正序),则应选用插人、冒泡或随机的快速排序为宜;(3)若n较大,则应采用时间复杂度为O(N×Log2(N))的排序方法:快速排序、堆排序或归并排序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;快速排序不适合用于“几乎已排好序”或“几乎正好倒序”的数据。在此最坏情况下,时间复杂度为O(N2)。堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。归并排序是稳定的,而且适用于数据量特别大以至于无法在内存中容纳,需要通过外存来进行的外部排序。
Shell排序的时间复杂度在数学上没有解决,大致可以认为是O(n(1+£)), 其中£是介于0和1之间的常数。
(二)查找算法
1.顺序查找法
即从第一个元素顺序到最后一个元素依次与待查的值进行比较,如果相等,查找成功,否则继续比较,直到所有元素都比较过了,如果还没有匹配的值,查找失败。查找适用于数据量少、不要求已经排序的数据,它的时间复杂度为O(N);
2.二分查找(折半查找)
又称折半查找,适用于数据量大、已经排序的数据,它的时间复杂度为O(Log2(N))。
二分查找的基本思想是(设R[low..high]是当前的查找区间) :
(1)首先确定该区间的中点位置:mid=(low+high)/2
(2)然后将待查的K值与R[mid].key比较:若相等,则查找成功并返回此位置,否则须确定新的查找区间,继续二分查找,具体方法如下:
①若R[mid].key>K,则由表的有序性可知R[mid..n].keys均大于K,因此若表中存在关键字等于K的结点,则该结点必定是在位置mid左边的子表R[1..mid-1]中,故新的查找区间是左子表R[1..mid-1]。
②类似地,若R[mid].key<K,则要查找的K必在mid的右子表R[mid+1..n]中,即新的查找区间是右子表R[mid+1..n]。下一次查找是针对新的查找区间进行的。
因此,从初始的查找区间R[1..n]开始,每经过一次与当前查找区间的中点位置上的结点关键字的比较,就可确定查找是否成功,不成功则当前的查找区间就缩小一半。这一过程重复直至找到关键字为K的结点,或者直至当前的查找区间为空(即查找失败)时为止。
3.分块查找
分块查找(Blocking Search)又称索引顺序查找。它是一种性能介于顺序查找和二分查找之间的查找方法。
分块查找表的存储结构由“分块有序”的线性表和索引表组成。
(1) “分块有序”的线性表
表R[1..n]均分为b块,前b-1块中结点个数为s=n/b,第b块的结点数小于等于s;每一块中的关键字不一定有序,但前一块中的最大关键字必须小于后一块中的最小关键字,即表是“分块有序”的。
(2)索引表
抽取各块中的最大关键字及其起始位置构成一个索引表ID[l..b],即:ID[i](1≤i≤b)中存放第i块的最大关键字及该块在表R中的起始位置。由于表R是分块有序的,所以索引表是一个递增有序表。
分块查找的基本思想是:
(1)首先查找索引表,索引表是有序表,可采用二分查找或顺序查找,以确定待查的结点在哪一块。
(2)然后在已确定的块中进行顺序查找,由于块内无序,只能用顺序查找。
4.对查找算法的总结
(1)若n较小(如n≤40),可采用顺序查找。 (2)若文件初始状态有序,且n较大,则应采用时间复杂度为O(Log2(N))的二分查找方法。(3) 若文件初始状态分块有序 ,且n较大,则应采用分块查找。
5 二叉排序树查找
稳定排序的概念:
在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的。
只要有一种数据能使排序相对次序发生变化,就是不稳定的。
稳定排序:
直接插入排序;冒泡排序;归并排序……;
不稳定排序:
希尔排序,快排,直接选择排序.堆排……