排序算法一:直接插入排序

排序算法


声明:引用请注明出处http://blog.csdn.net/lg1259156776/


引言

在我的博文《“主宰世界”的10种算法短评》中给出的首个算法就是高效的排序算法。本文将对排序算法做一个全面的梳理,从最简单的“冒泡”到高效的堆排序等。


排序相关的的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
    • 数据表( data list): 它是待排序数据对象的有限集合。
    • 排序码(key):通常数据对象有多个属性域,即多个数据成员组成,其中有一个属性域可用来区分对象,作为排序依据。该域即为排序码。每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类
    • 内排序:指在排序期间数据对象全部存放在内存的排序;
    • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

排序算法的分析

排序算法的稳定性

如果在对象序列中有两个对象r[i]r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算

空间开销

算法执行时所需的附加存储。


插入排序(Insert Sorting)

基本思想

每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

分类

根据寻找插入位置方法分为

  • 直接插入排序
  • 折半(二分)插入排序
  • 希尔插入排序

直接插入排序

基本思想

当插入第i(i1)个对象时,前面的V[0],V[1],,V[i1]已经排好序。这时,用V[i]的排序码与V[i1],V[i2],,V[0]的排序码顺序进行比较,找到插入位置即将V[i]插入,原来位置上的对象向后顺移。

直接插入排序图示

这里写图片描述

从上到下,分别展示了直接排序算法的所有可能的过程,包括相同排序码的排序方式(保持了原来的顺序,说明是稳定排序)以及in-place操作中的元素移动等。

这里写图片描述

直接插入排序算法分析

设待排序对象个数为n,则该算法的主程序执行n1排序码比较次数和对象移动次数与对象排序码的初始排列有关

  • 最好情况下,排序前对象已经按照要求的有序。比较次数(KCN):n1 ; 移动次数(RMN):为0。则对应的时间复杂度为O(n)
  • 最坏情况下,排序前对象为要求的顺序的反序。第i趟时第i个对象必须与前面i个对象都做排序码比较,并且每做1次比较就要做1次数据移动(具体可以从下面给出的代码中看出)。比较次数(KCN):n1i=1i=n(n1)2n22 ; 移动次数(RMN):为n1i=1i=n(n1)2n22。则对应的时间复杂度为O(n2)
  • 如果排序记录是随机的,那么根据概率相同的原则,在平均情况下的排序码比较次数和对象移动次数约为n24,因此,直接插入排序的时间复杂度O(n2)

直接插入排序算法的特点

  • 它是稳定排序,不改变相同元素原来的顺序。
  • 它是in-place排序,只需要O(1)的额外内存空间。
  • 它是在线排序,可以边接收数据边排序。
  • 它跟我们牌扑克牌的方式相似。
  • 对小数据集是有效的。

To save memory, most implementations use an in-place sort that works by moving the current item past the already sorted items and repeatedly swapping it with the preceding item until it is in place.

直接排序的代码(C++版本)

伪代码如下:

for i = 1, n
j = i
while(j > 0 and E[j] < E[j-1])
     swap(E[j], E[j-1])
     j--

C++代码

#include <iostream>
#include <iomanip>

using namespace std;

void swap(int &x, int &y)
{
    int temp = x;
    x = y;
    y = temp;
}

void insertion(int a[], int sz)
{
    for(int i=1; i  < sz; i++) {
        int j = i;
        while(j > 0 && (a[j] < a[j-1])) {
            swap(a[j], a[j-1]);
            j--;
        }
        cout << endl;
        for (int k = 0; k < sz; k++) cout << setw(3) << a[k];
    }
}

int main()
{
    int a[] = { 15, 9, 8, 1, 4, 11, 7, 12, 13, 6, 5, 3, 16, 2, 10, 14};
    int size = sizeof(a)/sizeof(int);
    for (int i = 0; i < size; i++) cout << setw(3) << a[i];
    insertion(a, size);
    cout << endl;
    return 0;
}

过程输出:

15  9  8  1  4 11  7 12 13  6  5  3 16  2 10 14 

  9 15  8  1  4 11  7 12 13  6  5  3 16  2 10 14 

  8  9 15  1  4 11  7 12 13  6  5  3 16  2 10 14 

  1  8  9 15  4 11  7 12 13  6  5  3 16  2 10 14 

  1  4  8  9 15 11  7 12 13  6  5  3 16  2 10 14 

  1  4  8  9 11 15  7 12 13  6  5  3 16  2 10 14 

  1  4  7  8  9 11 15 12 13  6  5  3 16  2 10 14 

  1  4  7  8  9 11 12 15 13  6  5  3 16  2 10 14 

  1  4  7  8  9 11 12 13 15  6  5  3 16  2 10 14 

  1  4  6  7  8  9 11 12 13 15  5  3 16  2 10 14 

  1  4  5  6  7  8  9 11 12 13 15  3 16  2 10 14 

  1  3  4  5  6  7  8  9 11 12 13 15 16  2 10 14 

  1  3  4  5  6  7  8  9 11 12 13 15 16  2 10 14 

  1  2  3  4  5  6  7  8  9 11 12 13 15 16 10 14 

  1  2  3  4  5  6  7  8  9 10 11 12 13 15 16 14 

  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 

下面是使用链表的直接插入排序算法:

#include <iostream>

using namespace std;

struct List
{
    int data;
    struct List *next;
} ;

void printList(struct List *head)
{
    struct List* ptr = head;
    while(ptr) {
        cout << ptr->data << " " ;
        ptr = ptr->next;
    }
    cout << endl;
}

struct List* createList(int a[], int sz)
{
    struct List *head = new struct List;
    struct List *current = head;

    for(int i = 0; i < sz; i++) {
        current->data = a[i];
        if (i == sz - 1 ) {
            current->next = NULL;
            break;
        }
        current->next = new struct List;
        current = current->next;
    }

    return head;
}

struct List* insertion(struct List *head)
  {
      if(head == 0) return head;

      // unsorted list - from the 2nd element
      struct List *unsorted = head->next;
      while(unsorted != 0)
      {
          // take key as an element in the unsorted list.
          struct List *prev = 0;
          struct List *iter = head;
          struct List *key = unsorted;

          // iterate within the sorted list and find the position
          while(iter != 0)
          {
              if(iter->data < key->data)
              {
                  prev = iter;
                  iter = iter->next;
              }
               else
                  break;
          }
          unsorted = unsorted->next;
          // if reached the end of sorted list 
          if(iter == key) 
              continue;

          // note down the position to replace in a sorted list
          struct List *replace = iter;

          //move iter to end of the sorted list 
          while(iter->next != key) iter=iter->next;

          // link to the upsorted list
          iter->next = unsorted;

          // delete the key and replace it in sorted list
          if(prev == 0) {
              head = key;
          } else {
                prev->next = key;
          }
          key->next = replace;
          printList(head);
       }
       return head;
  }

int main()
{
    int a[] = { 15, 9, 8, 1, 4, 11, 7, 12, 13, 6, 5, 3, 16, 2, 10, 14};
    int size = sizeof(a)/sizeof(int);

    struct List *head = createList(a, size);
    printList(head);
    head = insertion(head);
    printList(head);

    cout << endl;
    return 0;
}

未完待续


2015-9-23 艺少

原文地址:https://www.cnblogs.com/huty/p/8519127.html