插入排序,二分插入排序,希爾排序思想與比較

直接插入排序的基本方法:每步將一個待排序的元素,按其排序碼的大小,插入到前面已經排好序的一組元素的適當位置上去,直到元素全部插入爲止。

插入排序(insert sorting)思想:當插入第i個元素時,前面的v[0],v[1],v[2]......v[i-1],已經排好序了.這時用v[i]的插入碼與v[i-1],v[i-2],......排序碼進行比較,找到插入的位置即插入v[i],原來位置上的元素從後向前依次後移。

時間複雜度:  平均比較次數O(n2),平均移動次數 O(n2).

直接插入排序是一種穩定的排序。元素大部分有序時效率會更高,這時比較次數和移動次數都會減少。

參考代碼: 

void Sort<T>::insertSort(DataList<T> &datalist, int n)
{
  if ( -1 == n)
  {
    for (int i = 1; i < datalist.m_nCurrentSize; i++)
    {
      insertSort(datalist, i);
    }
    return;
  }
  Element<T> temp = datalist.m_pvector[n];
  int j;
  for ( j = n; j > 0; j--)
  {
    if (temp > datalist.m_pvector[j-1])
    {
      break;
    }else
    {
      datalist.m_pvector[j] = datalist.m_pvector[j-1];
    }
  }
  datalist.m_pvector[j] = temp;
}

二分(折半)插入(Binary insert sort)排序基本思想:設在數據表中有一個元素序列v[0],v[1],v[2]......v[n].其中v[0],v[1],v[2]......v[i-1]是已經排好序的元素。在插入v[i]。利用折半搜索尋找v[i]的插入位置。

二分插入排序是一種穩定的排序。當n較大時,總排序碼比較次數比直接插入排序的最差情況好得多,但比最好情況要差,所元素初始序列已經按排序碼接近有序時,直接插入排序比二分插入排序比較次數少。二分插入排序元素移動次數與直接插入排序相同,依賴於元素初始序列。

參考代碼:

template <class T>
void Sort<T>::binaryInsert(DataList<T> &datalist, int n)
{
  if (-1 == n)
  {
    for (int i = 1; i < datalist.m_nCurrentSize; i++)
    {
      binaryInsert(datalist, i);
    }
    return;
  }
  Element<T> temp = datalist.m_pvector[n];
  int left = 0, right = n - 1;  
  while(left <= right)
  {
    int middle = (left + right) / 2;
    if (temp > datalist.m_pvector[middle])
    {
      left = middle + 1;
    }else
    {
      right = middle - 1;
    }
  }
  for (int j = n - 1; j >= left; j--)
  {
    datalist.m_pvector[j+1] = datalist.m_pvector[j];
  }
  datalist.m_pvector[left] = temp;
}

希爾排序(Shell sort)基本思想: 改進的直接插入算法。設待排序的元素序列有n個元素,首先取一整數gap(<n)作爲間隔,將全部元素分爲gap個子序列,所有距離爲gap的元素放在同一序列中,在每個子序列中分別進行直接插入排序。然後縮小gap,例如gap=gap/2,重複上述的子序列劃分與排序工作。開始由於gap取直大,每個子序列元素少,排序速度快,待排序後期,gap值逐漸變小,子序列元素變多,但由於前面的工作基礎,大多數元素已經有序,所以排序速度快。

希爾排序是一種不穩定的排序。

參考代碼:

void swap(int *a, int *b)
{
  int x;
  x = *a;
  *a = *b;
  *b = x;
}

void insertion_sort(int data[], int n, int increment)
{  
  int i, j;
  for (i = increment; i < n; i += increment)
  {
    for (j = i; j >= increment && data[j] < data[j-increment]; j -= increment)
    {
      swap(&data[j], &data[j-increment]); 
    }
  }
}

void shellsort(int data[], int n)
{
  int i, j;
  for (i = n / 2; i > 0; i /= 2)
  {
    for (j = 0; j < i; j++)
    {
      insertion_sort(data, n, i);
    }
  }
}

另一種參考代碼:

template <class T>
void Sort<T>::shellSort(DataList<T> &datalist, int gap /* = -1 */)
{
  if (-1 == gap)
  {
    int gap = datalist.m_nCurrentSize / 2;
    while(gap)
    {
      shellSort(datalist, gap);
      gap = gap / 2;
    }
    return;
  }
  for (int i = gap; i < datalist.m_nCurrentSize; i++)
  {
    insert(datalist, i, gap);
  }
}

template <class T>
void Sort<T>::insert(DataList<T> &dataList, int n, int gap)
{
for (int i = n; i >= gap; i -= gap)
{
if (dataList.m_pvector[i] < dataList.m_pvector[i-gap])
{
Element<T> temp = dataList.m_pvector[i];
dataList.m_pvector[i] = dataList.m_pvector[i-1];
dataList.m_pvector[i-1] = temp;
}
}
}

總結:以上三種排序方法的核心都是直接插入排序,直接插入排序對於大部分有序的序列排序時速度快。二分插入排序在直接插入的基本上改變了查找元素插入位置的方法,對於完全無序的序列來說,速度會變快,但是對開大部分有序的序列反而會更慢,希爾排序則利用直接插入排序對於大部分有序的序列速度快的特點,先讓大部分序列有序,以此來提高排序效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章