经典排序算法学习笔记3——插入排序

一、插入排序

工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

数据结构 数组
最差时间复杂度 O(n^2)
最优时间复杂度 O(n)
平均时间复杂度  O(n^2)
最差空间复杂度 总共 O(n) ,需要辅助空间O(1)

https://zh.wikipedia.org/wiki/%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F#.E7.AE.97.E6.B3.95.E6.8F.8F.E8.BF.B0

1、算法思想:

插入排序都采用in-place在数组上实现。

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

2、伪代码:

mark first element as sorted
for each unsorted element
  ‘extract‘ the element
  for i = lastSortedIndex to 0
    if currentSortedElement > extractedElement
      move sorted element to the right by 1
    else: insert extracted element

3、C实现:

void insertion_sort(int arr[], int len) {
    int i, j;
    int temp;
    for (i = 1; i < len; i++) {
        temp = arr[i]; //與已排序的數逐一比較,大於temp時,該數向後移
        for (j = i - 1; j >= 0 && arr[j] > temp; j--) //j循环到-1时,由于[[短路求值]](http://zh.wikipedia.org/wiki/短路求值),不会运算array[-1]
            arr[j + 1] = arr[j];
                arr[j+1] = temp; //被排序数放到正确的位置
    }
}

C++实现:

template<typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定大於(>)的運算子功能
void insertion_sort(T arr[], int len) {
    int i, j;
    T temp;
    for (i = 1; i < len; i++) {
        temp = arr[i];
        for (j = i - 1; j >= 0 && arr[j] > temp; j--)
            arr[j + 1] = arr[j];
        arr[i-1] = temp;
    }
}

4、复杂度分析:

(1)时间复杂度

 初始状态( n项)  正序  反序  无序(平均)
 第i趟比较次数  1  i  /
 总比较次数  n-1  n(n-1)/2  /
 第i趟移动次数  0  i  /
 总移动次数  0  n(n-1)/2  /
 时间复杂度  O(n)  O(n^2)  O(n^2)

(2)空间复杂度

在排序过程中仅需要一个元素的辅助空间,所以空间复杂度为为O(1)。

5、改进:

(1)折半插入排序:因为使用插入排序得到的前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。

(2)具体操作:

1、将待插入区域的首元素设置为a[low],末元素设置为a[high],则比较时将待插入元素与a[m],其中m=(low+high)/2相比较

2、

do{
    if(新元素<a[m])
        选择a[low]到a[m-1]为新的插入区域(即high=m-1)
    else
        选择a[m+1]到a[high]为新的插入区域(即low=m+1)
}while(low>high)

3、将此位置之后所有元素后移一位,并将新元素插入a[high+1]。

(3)C实现:

#include <stdio.h>
typedef int ElemType ;
ElemType arr[]={0,9,8,7,6,5,4,3,2,1};
ElemType n=10,i,j;
ElemType low,high,mid;
void BinSort(ElemType r[],ElemType n)
{
    for(i=2;i<=n;i++)
    {
        r[0]=r[i];
        low=1; high=i-1;
        while (low<=high)
        {
            mid=(low+high)/2;
            if(r[0]<r[mid])
                high=mid-1;
            else
                low=mid+1;}
        for(j=i-1;j>=low;j--)
        {
            r[i]=r[j];
            i--;
        }
        r[low]=r[0];} }
void put(ElemType r[],ElemType n)
{
    for(j=1;j<n;j++)
        printf("%d\t",r[j]);
    printf("\n");
}
void main()
{
    BinSort(arr,n);
    put(arr,n);
}

代码来源:http://baike.baidu.com/link?url=x12HcpirljXV_EWkGELhZEbwM1PBFMgZKENK6DspEH91gepF4ZkuHIdupjbBLqxJuYvTCDbBhupo41K81KZds_#4_3

(4)复杂度分析:

时间复杂度:O(n^2) //折半查找只是减少了比较次数,但是元素的移动次数不变,所以折半插入排序算法的时间复杂度仍然为O(n^2)

空间复杂度:O(1)

时间: 2024-10-26 13:39:43

经典排序算法学习笔记3——插入排序的相关文章

八大排序算法学习笔记:插入排序(一)

插入排序     包括:直接插入排序,二分插入排序(又称折半插入排序),链表插入排序,希尔排序(又称缩小增量排序).属于稳定排序的一种(通俗地讲,就是两个相等的数不会交换位置) . 直接插入排序: 1.算法的伪代码(这样便于理解):     INSERTION-SORT (A, n)             A[1 . . n] for j ←2 to n do key ← A[ j] i ← j – 1 while i > 0 and A[i] > key do A[i+1] ← A[i]

八大排序算法学习笔记:插入排序(二分插入排序)

二分插入排序   也称折半插入排序, 1.基本思想:设数列[0....n]分为两部分一部分是[0...i]为有序序列,另一部分是[i+1.....n]为无序序列,从无序序列中取一个数 x ,利用二分查找算法找到 x 在有序序列中的插入位置并插入,有序序列还是有序的,接下来重复上述步骤,直到无序序列全部插入有序序列 ,这是整个序列只剩下有序序列即有序了. 2.代码:    3.复杂度: 用二分插入排序所要进行的总比较次数为O(lgn),当n较大时,比直接插入排序的最大比较次数小得多,但大于最小比较

经典排序算法学习笔记之二——快速排序

一.快速排序 数据结构 不定 最差时间复杂度 O(n^2) 最优时间复杂度 O (n*log n) 平均时间复杂度 O (n*log n) 最差空间复杂度 根据实现的方式不同而不同 https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F 1.算法思想: 从数列中挑出一个元素,称为"基准"(pivot), 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边

经典排序算法学习笔记四——希尔排序

一.希尔排序 数据结构 数组 最差时间复杂度 根据步长序列的不同而不同.已知最好的:O(n*log ^{2}n) 最优时间复杂度 O(n) 平均时间复杂度 根据步长序列的不同而不同. 最差空间复杂度 O(n) 1.算法思想: 先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序: 然后取d2<d1,重复上述分组和排序操作: 直至di=1,即所有记录放进一个组中排序为止. 我是栗子,栗子,栗子 假设有这样一组数[ 13 14 94 33 82 25 59 94 65

经典排序算法学习笔记之一——冒泡排序

一.冒泡排序 1.算法思想: 冒泡排序算法的运作如下: 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数. 针对所有的元素重复以上的步骤,除了最后一个. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较. 2.伪代码: function bubble_sort (array, length) { var i, j; for(i from 0 to length-1){ for

经典排序算法学习笔记五——直接选择排序

一.直接选择排序 数据结构 数组 最差时间复杂度 O(n^2) 最优时间复杂度 O(n^2) 平均时间复杂度 O(n^2) 最差空间复杂度 О(n) total, O(1) auxiliary 1.算法思想: 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置. 然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾. 以此类推,直到所有元素均排序完毕. 2.伪代码: repeat (numOfElements - 1) times set the first uns

经典排序算法学习笔记七——堆排序

堆排序 数据结构 数组 最差时间复杂度 O(n*log n) 最优时间复杂度 O(n*log n) 平均时间复杂度 O(n*log n) 最差空间复杂度 О(n) total, O(1) auxiliary 1.堆的基础知识 堆节点的访问 通常堆是通过一维数组来实现的.在数组起始位置为0的情形中: 父节点i的左子节点在位置(2*i+1); 父节点i的右子节点在位置(2*i+2); 子节点i的父节点在位置floor((i-1)/2); 堆的操作 在堆的数据结构中,堆中的最大值总是位于根节点.堆中定

[算法学习笔记]直接插入排序笔记

直接插入排序概念: 带排元素放在elem[0...n-1]中,初始化时,elem[0]自成1个有序区,无序区为elem[1...n-1],从i=1起,到i=n-1,依次将elem[i]插入有序区[0...n-1]中 直接插入排序算法步骤: 1.在当前有序区域R[1,i-1]中查找R[i]的正确插入位置K(1<=K<=i-1) 2.将R[K,i-1]中的记录均向后移动 3.移动后腾出K位置,插入R[i] (最坏)时间复杂度:O(n^2) 空间复杂度:O(1) /// <summary>

八大排序算法学习笔记:冒泡排序

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端. 算法原理: 比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. 针对所有