排序 Sorting

  • 选择排序(Selection Sorts)
  • 交换排序(Exchange Sorts)
  • 插入排序(Insertion Sorts)
  • 间接排序(Indirect Sorts)
  • 折半插入排序(Binary Insertion Sorts)
  • 希尔排序(Shell Sorts)

选择排序(Selection Sorts)

选择排序(Selection Sorts) 是对列表或者列表的一部分进行多次扫描,每一选出一个元素(最大/最小)将其放到正确位置。 —— [ 数据结构与算法分析C++ ]

对于一个序列: 67, 33, 21, 84, 49, 50, 75 。
第一次扫描(从第一个元素开始):最小元素为21, 将其与第一个元素交换,得到:
21, 33, 67, 84, 49, 50 ,75 。
第二次扫描(从第二个元素开始):最小元素为33,将其与第二个元素交换,得到:
21, 33, 67, 84, 49, 50 ,75 。
第三次:21, 33, 49, 84, 67, 50 ,75 。
第四次:21, 33, 49, 50, 67, 84 ,75 。
第五次:21, 33, 49, 50, 67, 84 ,75 。
第六次:21, 33, 49, 50, 67, 75 ,84。
序列中共有7个元素,进行了 (7-1)= 6次扫描。
分别进行了6(假设第一个元素为最小元素,与第二个元素比较,记下较小元素的索引,然后再与第三个元素比较并记下最小元素的索引,。。。,与第七个元素比较,记下最小元素索引,7个元素6次比较) , 5 , 4,3 , 2 , 1(第六次扫描将倒数第二个元素和最后一个元素比较)次比较。
如果序列中有n个元素,总共比较次数为:
(n1)+(n2)+...+2+1=(n1)(n1+1)2=n(n1)2
时间复杂度为: O(n2) ;

交换排序(Exchange Sorts)

交换排序(Exchange Sorts) 是两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。 —— [交换排序算法]
典型地,冒泡排序就是交换排序。

对于一个序列: 67, 33, 21, 84, 49, 50, 75 。
第一次扫描: 67与33交换, 33, 67, 21, 84, 49, 50, 75 。
67与21交换,33, 21, 67, 84, 49, 50, 75 。
67与84不交换,33, 21, 67, 84, 49, 50, 75 。
84与49交换,33, 21, 67, 49, 84, 50, 75 。
84与50交换,33, 21, 67, 49, 50, 84, 75 。
84与75交换,33, 21, 67, 49, 50, 75, 84 。
这样经过第一轮扫描,最大的数就被放到了最后一个位置。
在第二轮扫描时,排除最后一项,对钱6个元素进行比较和位置交换。扫描共6次,比较次数分别为6,5,4,3,2,1次。
如果序列中有n个元素,总共比较次数为:
(n1)+(n2)+...+2+1=(n1)(n1+1)2=n(n1)2
时间复杂度为: O(n2) ;

插入排序(Insertion Sorts)

插入排序(Insertion Sorts)是反复的将新的元素插入到一个有序的列表中,令插入后的列表也是有序的。 —— [ 数据结构与算法分析C++ ]

对于一个序列: 67, 33, 21, 84, 49, 50, 75 。
假设该数组(7个元素)索引为1~7。0存放将要插入元素的副本。而且默认第一个元素为已经排好序的元素。

第一次扫描(比较2次):
从第二个元素开始(j=2),arr[0]=33, 让33与arr[1]的67比较,33<67,将67覆盖到arr[2]位置上,j–, 33与arr[0]上的33比较,33不小于67,while循环终止,arr[1] = 33。
此时序列为: 3367, 21, 84, 49, 50, 75 。
第二次扫描(比较3次):
再从第三个元素开始(j=3) , arr[0]=21, 21与arr[2]的67比较,21<67,,强67覆盖到arr[2]位置上,j–,21与arr[1]上的33比较,21<33,将33覆盖到arr[1]的位置上,j–,21与arr[0]比较,21不小于21,while循环结束。让arr[j]的值等于21(此时的j=1)。
此时序列为: 213367, 84, 49, 50, 75 。
以此类推,剩下的比较次数分别为:4 , 5 , 6 , 7次。
如果序列中有n个元素,总共比较次数为:
2+3+...+n=(1+2+3+...+n)1= n(n+1)21
时间复杂度为: O(n2) ;

间接排序(Indirect Sorts)

间接排序(Indirect Sorts)通过双层索引的方式,通过修改内层索引index[i]表示的值,使得即使i仍然是从1到n,但是index[i]的值不再是1到n,而是使得数组变得有序的值。这样,arr[index[i]]就是一个有序的列表。 —— 朱勇
对于一个序列: 67, 33, 21, 84 。
arr[1] = 67, arr[2] = 33, arr[3] = 21 , arr[4] = 84 。
令index[1] = 1, index[2] = 2, index[3] = 3, index[4] = 4,如果要让数组arr变得有序就要让index[1] = 3, index[2] = 2, index[3] = 1, index[4] = 4。
这种方法,就叫做间接排序法,不移动数据,只修改索引指向。

折半插入排序(Binary Insertion Sorts)

折半插入排序(Binary Insertion Sorts)是对插入排序的一种改进,在前面的插入排序中,不难发现,每次插入之后的序列都是一个有序的序列。这时,我们可以引入在查找算法中的一个二分查找(或折半查找binary search)。这样就可以减少我们的比较次数。

时间复杂度为: O(n2) .
为啥叻:比较次数虽然略有降低,但是最坏情况下,移动的次数仍然是那么多次。
Binary insertion sort employs a binary search to determine the correct location to insert new elements, and therefore performs log2(n) comparisons in the worst case, which is O(n log n). The algorithm as a whole still has a running time of O(n2) on average because of the series of swaps required for each insertion. —— 维基百科
意思是说,二分插入排序(折半插入排序)使用了二分搜索的方式,来决定新元素的正确插入位置。因此,在最坏的情况下比较 log2n 次,时间复杂度为 nlogn . 在整体上,该算法还是有 O(n2) 平均时间复杂度。因为每一次插入带来了交换操作。

希尔排序(Shell Sorts)

希尔排序(Shell Sorts):以它的发明者Donald Shell命名,该算法在1959公之于众. 希尔排序是基于一个增量序列的交叉插入排序,它也属于插入排序的范畴,一个改进的版本。当这个增量递减到1的时候,该序列就被排好了。
这个方法开始时,两个互相比较的数相距比较远,然后逐渐的缩小互相比较的元素之间的间距(gap)。由此可知希尔排序的运行时间很大程度上依赖于gap序列的选取。
比如在Wikipedia中:

选择的gap序列分别为5 , 3 , 1。
The question of deciding which gap sequence to use is difficult. Every gap sequence that contains 1 yields a correct sort; however, the properties of thus obtained versions of Shellsort may be very different.
至于决定选用哪个gap序列是相当困难的。包含1的gap序列会产生正确的结果。因此,对于一个序列,相应的gap序列也不尽相同。
The table below compares most proposed gap sequences published so far. Some of them have decreasing elements that depend on the size of the sorted array (N). Others are increasing infinite sequences, whose elements less than N should be used in reverse order.
这里有一些推荐的gap选取序列方法。可以看到当选取序列为1,2,3,5,9,17,33,65…时,时间复杂度为 O(N32)

你可能感兴趣的:(排序)