数据结构中排序和查找的算法

来源:互联网 发布:淘宝宝贝拍照 编辑:程序博客网 时间:2024/04/30 06:33
(一)排序算法

    排序算法是一种基本并且常用的算法。由于实际工作中要处理的数据量巨大,所以对排序算法有很高的速度要求。而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。O方法的定义:

    若存在一个常量K和起点n0,使当n>=n0时,有f(n)<=K×g(n),则f(n) = O(g(n))。

    我们将按照算法的复杂度,从简单到复杂来分析算法。影响我们算法性能的主要部分是比较和交换,显然,比较和交换次数越多,性能就越差。按照关键字相同的元素在排序前后的相对位置是否改变,排序算法可以分为稳定的和不稳定的。

    第一部分是简单排序算法,它们的共同点是算法复杂度为O(N2)。

    第二部分是高级排序算法,复杂度为O(N×Log2(N))或小于O(N2)。这里我们只介绍3种算法。另外还有几种算法因为涉及树与堆的概念,这里不再详细讨论。

1、简单排序算法

1)冒泡法

这是最原始,也是众所周知的最慢的算法。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R:凡扫描到违反本原则的轻气泡,就使其向上“飘浮”。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。

2)选择法

这种方法提高了一点性能(某些情况下),这种方法类似我们人为的排序习惯:从数据中选择最小的同第一个值交换,再从剩下的部分中选择最小的与第二个交换,这样往复下去。

3)插入法

插入法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张。

2、高级排序算法

1)快速排序

快速排序的基本思想是基于分治策略的。将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。首先我们选择一个中间值middle(程序中我们使用数组中间值),然后把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使用这个过程。

2)Shell排序(希尔排序)

首先需要一个递减的步长gap,最后的步长必须是1。工作原理是首先对相隔较远的元素的所有内容排序,然后再使用同样的方法对相隔近些的元素的排序,以此类推。

3)归并排序

把数据等分成两部分, 各自用归并排序排好后再合并,它在归并时耗费O(n)的空间。

3、对排序算法的总结

(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较大,则应采用分块查找。

原创粉丝点击