zoukankan      html  css  js  c++  java
  • 基础知识-排序算法

    基础知识复习与整理,内容摘抄于维基百科,推荐一个在线学习的网站: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    
    
  • 相关阅读:
    热更新--动态加载framework
    封装framework注意点
    zip压缩和解压缩
    iOS 网络请求数据缓存
    tomcat服务器访问网址组成
    iOS--支付宝环境集成
    线程10--NSOperation的基本操作
    线程9--NSOperation
    线程8--GCD常见用法
    线程7--GCD的基本使用
  • 原文地址:https://www.cnblogs.com/luckjun/p/5209198.html
Copyright © 2011-2022 走看看