zoukankan      html  css  js  c++  java
  • 【经典算法】基本的排序算法:插入排序

    引言

    An insertion sort starts by considering the two first elements of the array data,which are data[0] and data[1]. if they are out of order, and interchange takes place. Then,the third element, data[2], is considered and inserted into its proper place.If data[2] is less than data[0] and data[1],these two elements are shifted by on position; data[0] is place at position  i, data[1] at position 2,and data[2] at position 0. If data[2] is less than data[1] and not less than data[0],then only data[1] is moved to position 2 and its place is taken by data[2]. If finally, data[2] is not less than both its predecessors,it stays in its current position,Each element data[i] is inserted into its proper location j such the 0<=j<=i, and all elements greater than data[i] are moved by one position.

    译: 插入排序首先考虑data中的前两个元素,即data[0]和data[1]。如果它们的次序颠倒了,就交换它们。然后,考虑第三个元素data[2],将其插入到合适的位置上。如果data[2]同时小于data[0]和data[1],那么data[0]和data[1]都要移动一个位置;data[0]放在位置1上,data[1]放在位置2上,而将data[2]放在位置0上。如果data[2]小于data[1],而不于data[0],那么只须把data[1]移动到位置2上,并由data[2]占据它的位置。最后,如果data[2]不小于前两个元素,它将保留在当前的位置。每一个元素data[i]都要插入到合适的位置j上,使0<=j<=i,所有比data[i]大的元素都要移动一个位置。

    插入排序算法伪码与实现

    插入排序算法的要点如下:

    insertionsort(data[],n){
      for(i=1; i<n; i++)
         move all elements data[j] greater than data[i] by one position;
         place data[i] in its proper position;
    }

    注意,在每次迭代中,排序只限于数组的一小部分,并且只在最后一次迭代中才涉及到整个数组。如下图所示是当对数组[5 2 3 8 1]行insertionsort()方法时,数组所发生的一系变动。

    因数组中只有一个元素已排序,所以算法从第二元素位置即位置1开始排序。接着,对于每一个元素tmp = data[i],所有比tmp大的位素都要复制到下一位置上,而把tmp放在合适的位置上。

    实现代码如下:

    template< class T>
    void insertionsort(T data[], int n){
            for(int i =1, j; i<n; i++){
                T tmp = data[i];
                for(j =i; i>0&&tmp< data[j-1]; j--)
                     data[j] = data[j-1];
                data[j] =tmp;
            }
    }

    插入排序的一个优点是只有需要时才对数组排序。如果数组已经排好序了,就不再对数组进行移动;只有变量tmp得到初始化,存储在变量中的值返回值原位置。可以识别出已排序的数组部分,并相应停止,但忽视元素可以已在合适位置上的事实。一个缺点是:如果插入数据项,所有比插入元素大的元素都必须移动。插入操作不是局部的,可能需要移动大量的元素。

    算法分析

    为了获取insertionsort()算法执行的移动和比较次数,首先要注意,外层的for语句执行n-1次。但是,比data[i]大的元素移动一个位置的次数并不总是相同的。

    最好的情况是:数据已排好序。对于每个位置i,只需比较一匀,这样就只需进行n-1次比较(其数量级是o(n))和2(n-1)次移动,所有的移动和比较都是多余的。最坏的情况是:数据按相反顺序排序。在这种情况下,对于外层for的每次迭代i,都比较i次,即所有迭代的比较总数是


    内层for中的赋值次数可以用相同的公式计算。把tmp在外层for中加载和卸载的次数加起来,得到总的移动次数:

    前面我们只考虑了极端情况。如果数据是随机排序的,结果如何呢?假设数据项占用数组单元的概率相等,在外层for的迭代i中,data[i]与其它元素的平均比较次数计算如下:

    为了求得所有比较次数的平均值,对于所有的迭代i来说,都必须从1开始一直累加到n-1为止。结果是


    它的时间复杂度是O(n^2),大约是最坏情况下的比较次数的1/2。按照相同的方式,可以确定在外层for的迭代i中,data[i]需要移动0,1,..i-1次:即

    次,加上一定分会发生的两次移动。因此,在外层for中所有迭代中,平均移动次数为

    其中时间复杂度为O(n^2)。

    综上所述,对于随机顺序的数组来说,移动和比较的次数是与最好情况接近,还是与最坏情况接近?遗憾的是,它接近于后者,即:当数组的元素加倍时,平均需要付出4倍的努力来排序。

    参考文献

    [1] Adam Drozdek , Data Structures and Algorithms in C++,Third Edition.

    =========================================================

    转载请注明出处:http://blog.csdn.net/ songzitea/article/details/8864084
    =========================================================
  • 相关阅读:
    Largest Rectangle in Histogram
    Valid Sudoku
    Set Matrix Zeroes
    Unique Paths
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Path Sum II
    Path Sum
    Validate Binary Search Tree
    新手程序员 e
  • 原文地址:https://www.cnblogs.com/riskyer/p/3281358.html
Copyright © 2011-2022 走看看