程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C說話中疾速排序和拔出排序優化的完成

C說話中疾速排序和拔出排序優化的完成

編輯:關於C++

C說話中疾速排序和拔出排序優化的完成。本站提示廣大學習愛好者:(C說話中疾速排序和拔出排序優化的完成)文章只能為提供參考,不一定能成為您想要的結果。以下是C說話中疾速排序和拔出排序優化的完成正文


疾速排序
疾速排序思惟

    1962年,由C.A.R.Hoare發明出來。該算法焦點思惟就一句話:“排序數組時,將數組分紅兩個小部門,然後對它們遞歸排序”。但是采用甚麼樣的戰略將數組分紅兩個部門是症結,想一想看,假如隨意將數組A分紅A1和A2兩個小部門,即使分離將A1和A2排好序,那末A1和A2從新組分解A時依然是無序的。所以,我們可以在數組中找一個值,稱為key值,我們在把數組A分化為A1和A2前先對A做一些處置,讓小於key值的元素都移到其右邊,一切年夜於key值的元素都移到其左邊。如許遞歸排序A1和A2,數組A就排好了。

舉例

    我們要排序的數組以下:

55 41 59 26 53 58 97 93

    我們拔取第一個元素作為key值,即55.(普通都是拔取第一個元素)。假設我們有一種方法可以將數組做一步預處置,讓小於key值的元素都位於其右邊,年夜於key值的元素都位於其左邊,預處置完數組以下:

41 26 53 55 59 58 97 93 

    如許數組就被key值劃分紅了兩段,A[0...2]小於key,A[4...7]年夜於key,可見key值自己已排好序,接上去對A[0...2]和A[4...7]分離停止遞歸排序,那末全部數組就排好序了。預處置做的任務再次廓清下:找一個key值,把key位放到某地位A[p],使小於key值的元素都位於A[p]右邊,年夜於key值的元素都位於A[p]的左邊。到此,我們的快排模子就成型了。

/*l, u 代表待排序部門的下界和上界*/
void qsort(l, u)
{
 /*遞歸停止前提是待排序部門的元素個數小於2*/
 if(l >= u)
 {
  return;
 }
 
 /*此處停止預處置,預處置後key值位於地位p*/
 
 qsort(l, p-1);
 qsort(p+1, u);
}

     接上去看若何做預處置。我們拔取A[0]做為key值, p作為key值的地位。我們從A[1]開端遍歷前面的數組,用變量i指導今朝的地位,每次找到小於key的值都與A[++p]交流。開端時p=0.

55 41 59 26 53 58 97 93 i = 1,A[i]地位為41, 即A[i] < key, swap(++p , i),即p = 1:
55 41 59 26 53 58 97 93 i = 2,A[i]地位為59,A[i] > key,不做任何轉變。
i = 3,A[i]地位為26,A[i] < key,swap(++p, i), 即p = 2:
55 41 26 59 53 58 97 93 i = 4,A[i]地位為53,A[i] < key,swap(++p, i),p = 3:
55 41 26 53 59 58 97 93 i = 5,A[i]地位為58,A[i] > key,不做任何轉變。
i = 6,A[i]地位為97,A[i] > key,不做任何轉變.
i = 7,A[i]地位為93,A[i] > key,不做任何轉變.停止輪回。此時p為key的終究地位。還需一步把key值填入p地位。
最初swap(l, p)即把Key值放到終究地位上了。至於為何要交流l,p的地位,可以另拿一組數據試一下:55,41,59,26,99,58,97,93。

完全的法式1

/*l, u 代表待排序部門的下界和上界*/

void qsort(int l, int u)
{
 /*遞歸停止前提是待排序部門的元素個數小於2*/
 if(l >= u)
 {
  return;
 }
 
 int p = l;
 for(int i = l+1; i <= u; i++)
 {
  if(A[i] < A[l])
  {
   swap(++p, i);
  }
 }
 swap(l, p);
 
 qsort(l, p-1);
 qsort(p+1, u);
}

這就是第一代疾速排序算法,正常情形下其龐雜度為nlogn,但在斟酌一種極端情形:n個雷同元素構成的數組。在n-1次劃分中每次劃分都須要O(n)的時光,所以總的時光為O(n^2)。應用雙向劃分便可以免這個成績。

雙向劃分疾速排序

/*l, u 代表待排序部門的下界和上界*/
void qsort(int l, int u)
{
 /*遞歸停止前提是待排序部門的元素個數小於2*/
 if(l >= u)
 {
  return;
 }
 
 key = A[l]
 for(int i = l, j = u+1; i <= j;)
 {
  do i++ while(i <= u && A[i] < key));
  do j-- while(A[j] > key);
  if(i > j)
  {
   break;
  }
  swap(i, j);
 }
 swap(l, j);
 
 qsort(l, j-1);
 qsort(j+1, u);
}

拔出排序優化
拔出排序的精華就是起首將第一個元素視為有序子數組x[0...0],然後拔出x[1]...x[n-1].思惟很簡略,代碼也很簡略,簡略的代碼有無優化的空間呢?編程珠玑中供給了幾個優化後的計劃,效力進步了70%之多。

簡略的完成(sort1)

void insertSort(int *array, size_t size)
{
 for(size_t i = 1; i < size; i++)
 {
  for(int j = i; j > 0 && array[j - 1] > array[j]; j--)
  {
   swap(array[j - 1], array[j]);
  }
 }
}

優化思緒
    內輪回的swap函數能夠不如內聯函數快些,所以第一步優化將該swap函數睜開,據作者說,睜開後效力進步了60%。

優化代碼(sort2)

void insertSort(int *array, size_t size)
{
 for(size_t i = 1; i < size; i++)
 {
  for(int j = i; j > 0 && array[j - 1] > array[j]; j--)
  {
   int t = array[j];
   array[j] = array[j - 1];
   array[j - 1] = t;
  }
 }
}

優化思緒
    因為內輪回中老是給變量t賦異樣的值(x[i]的初始值),所之內輪回關於t的兩條賦值語句移出輪回,聽說這麼做的效力又進步了15%。

優化代碼(sort3)

void insertSort(int *array, size_t size)
{
 for(size_t i = 1; i < size; i++)
 {
  int j = i;
  int t = array[j];
  for(; j > 0 && array[j - 1] > array[j]; j--)
  {
   array[j] = array[j - 1];
  }
  array[j] = t;
 }
}

《編程珠玑》書中給出了三種排序的運轉時光:

拔出排序的效力老是O(n2),效力差在比擬的次數和交流的頻率,假如交流的頻率削減的話便可以年夜年夜進步拔出排序的效力,這也是為何元素根本有序時拔出排序效力高的緣由。

小我不雅點

    代碼調優和機能優化都能夠帶來一系列的反作用,好比法式的准確性,可讀性,可保護性等。能否須要調優要看成績性質,調優既是脆而不堅的“花活”,也是一把芒刃,差別就在於應用的場所。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved