基础知识-排序算法

基础知识复习与整理,内容摘抄于维基百科,推荐一个在线学习的网站:visualgo.net

排序算法常规分类

  • 计算的时间复杂度(最差、平均、和最好性能),依据列表(list)的大小(n)。一般而言,好的性能是O(n log n),且坏的性能是O(n2)。对于一个排序理想的性能是O(n)。仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要O(n log n)。
  • 存储器使用量(以及其他电脑资源的使用)
  • 稳定性:稳定排序算法会让原本有相等键值的纪录维持相对次序。也就是如果一个排序算法是稳定的,当有两个相等键值的纪录R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。
  • 依据排序的方法:插入、交换、选择、合并等等。

常用排序算法


稳定的排序

  • 冒泡排序(bubble sort)— O(n2)
  • 鸡尾酒排序(cocktail sort)—O(n2)
  • 插入排序(insertion sort)—O(n2)
  • 桶排序(bucket sort)—O(n);需要O(k)额外空间
  • 计数排序(counting sort)—O(n+k);需要O(n+k)额外空间
  • 归并排序(merge sort)—O(n log n);需要O(n)额外空间
  • 原地归并排序— O(n log2 n)如果使用最佳的现在版本
  • 二叉排序树排序(binary tree sort)— O(n log n)期望时间;O(n2)最坏时间;需要O(n)额外空间
  • 鸽巢排序(pigeonhole sort)—O(n+k);需要O(k)额外空间
  • 基数排序(radix sort)—O(n·k);需要O(n)额外空间
  • 侏儒排序(gnome sort)— O(n2)
  • 图书馆排序(library sort)— O(n log n)期望时间;O(n2)最坏时间;需要(1+ε)n额外空间
  • 块排序(block sort)— O(n log n)

**不稳定的排序 **

  • 选择排序(selection sort)—O(n2)
  • 希尔排序(shell sort)—O(n log2 n)如果使用最佳的现在版本
  • Clover排序算法(Clover sort)—O(n)期望时间,O(n2)最坏情况
  • 梳排序— O(n log n)
  • 堆排序(heap sort)—O(n log n)
  • 平滑排序(smooth sort)— O(n log n)
  • 快速排序(quick sort)—O(n log n)期望时间,O(n2)最坏情况;对于大的、随机数列表一般相信是最快的已知排序
  • 内省排序(introsort)—O(n log n)
  • 耐心排序(patience sort)—O(n log n + k)最坏情况时间,需要额外的O(n + k)空间,也需要找到最长的递增子序列(longest increasing subsequence)

不实用的排序

  • Bogo排序— O(n × n!),最坏的情况下期望时间为无穷。
  • Stupid排序—O(n3);递归版本需要O(n2)额外存储器
  • 珠排序(bead sort)— O(n) or O(√n),但需要特别的硬件
  • 煎饼排序—O(n),但需要特别的硬件
  • 臭皮匠排序(stooge sort)算法简单,但需要约n^2.7的时间

冒泡排序


入门算法,对有序序列排序时有劣势,一般建议用插入排序替代。也可以在内部循环时,可以做个标记变量,减少对有序序列排序时的循环,若在每次走访数列时,把走访顺序反过来,也可以稍微地改进效率。有时候称为鸡尾酒排序,因为算法会从数列的一端到另一端之间穿梭往返。

维基上的助记码

i∈[0,N-1)                //循环N-1遍
   j∈[0,N-1-i)            //每遍循环要处理的无序部分
     swap(j,j+1)          //两两排序(升序/降序)

C#版本

static void BubbleSort(int[] intArray) {
    int temp = 0;//存储临时变量
    for (int i = 0; i < intArray.Length; i++)
        for (int j = i - 1; j >= 0; j--)
            if (intArray[j + 1] < intArray[j]) {
                temp = intArray[j + 1];
                intArray[j + 1] = intArray[j];
                intArray[j] = temp;
            }
}

Python版本


def bubble(List):
    for j in range(len(List)-1,0,-1):
        for i in range(0,j):
            if List[i]>List[i+1]:List[i],List[i+1]=List[i+1],List[i]
    return List

鸡尾酒排序


鸡尾酒排序,也就是定向冒泡排序,鸡尾酒搅拌排序,搅拌排序(也可以视作选择排序的一种变形),涟漪排序,来回排序or 快乐小时排序,是冒泡排序的一种变形。此算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。

伪代码

function cocktail_sort(list, list_length){ // the first element of list has index 0
    bottom = 0;
    top = list_length - 1;
    swapped = true; 
    while(swapped == true) //如果没有交换发生,序列就已经是有序的了
    {
        swapped = false; 
        for(i = bottom; i < top; i = i + 1)
        {
            if(list[i] > list[i + 1])  
            {
                swap(list[i], list[i + 1]); 
                swapped = true;
            }
        }
        // decreases top the because the element with the largest value in the unsorted
        // part of the list is now on the position top 
        top = top - 1; 
        for(i = top; i > bottom; i = i - 1)
        {
            if(list[i] < list[i - 1]) 
            {
                swap(list[i], list[i - 1]);
                swapped = true;
            }
        }
        // increases bottom because the element with the smallest value in the unsorted 
        // part of the list is now on the position bottom 
        bottom = bottom + 1;  
    }
}

与冒泡排序不同的地方

鸡尾酒排序等于是冒泡排序的轻微变形。不同的地方在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。

以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问一次序列就可以完成排序,但如果使用冒泡排序则需要四次。但是在乱数序列的状态下,鸡尾酒排序与冒泡排序的效率都很差劲。

插入排序


插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)
具体算法描述如下:

  • 从第一个元素开始,该元素可以认为已经被排序
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置
  • 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  • 将新元素插入到该位置后
  • 重复步骤2~5

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找插入排序。

C#实现

public static void InsertSort(double[] data) {
	int i, j;
	var count = data.Length;
	for (i = 1 ; i < count ; i++) {
		var t = data[i];
		for(j = i - 1; j >= 0 && data[j] > t; j--)
			data[j + 1] = data[j];
		data[j + 1] = t;
	}
}

Python

def insertion_sort(n):
    if len(n) == 1:
        return n
    b = insertion_sort(n[1:])
    m = len(b)
    for i in range(m):
        if n[0] <= b[i]:
            return b[:i]+[n[0]]+b[i:]
    return b + [n[0]]

#版本2    
def insertion_sort(lst):
    if len(lst) == 1:
        return

    for i in xrange(1, len(lst)):
        temp = lst[i]
        j = i - 1
        while j >= 0 and temp < lst[j]:
            lst[j + 1] = lst[j]
            j -= 1
        lst[j + 1] = temp    
posted @ 2016-02-23 10:58  Frida-  阅读(1673)  评论(0编辑  收藏  举报