最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++線性時(shí)間的排序算法分析

 更新時(shí)間:2014年08月14日 11:27:22   投稿:shichen2014  
這篇文章主要介紹了C++線性時(shí)間的排序算法分析,是非常經(jīng)典的非比較排序算法,對(duì)于C++程序員有很大的借鑒價(jià)值,需要的朋友可以參考下

前面的文章已經(jīng)介紹了幾種排序算法,如插入排序(直接插入排序,折半插入排序,希爾排序)、交換排序(冒泡排序,快速排序)、選擇排序(簡(jiǎn)單選擇排序,堆排序)、2-路歸并排序(可以參考前一篇文章:各種內(nèi)部排序算法的實(shí)現(xiàn))等,這些排序算法都有一個(gè)共同的特點(diǎn),就是基于比較。

本文將介紹三種非比較的排序算法:計(jì)數(shù)排序,基數(shù)排序,桶排序。它們將突破比較排序的Ω(nlgn)下界,以線性時(shí)間運(yùn)行。

一、比較排序算法的時(shí)間下界

所謂的比較排序是指通過(guò)比較來(lái)決定元素間的相對(duì)次序。

“定理:對(duì)于含n個(gè)元素的一個(gè)輸入序列,任何比較排序算法在最壞情況下,都需要做Ω(nlgn)次比較?!?br /> 也就是說(shuō),比較排序算法的運(yùn)行速度不會(huì)快于nlgn,這就是基于比較的排序算法的時(shí)間下界。

通過(guò)決策樹(shù)(Decision-Tree)可以證明這個(gè)定理,關(guān)于決策樹(shù)的定義以及證明過(guò)程在這里就不贅述了。讀者可以自己去查找資料,這里推薦大家看一看麻省理工學(xué)院公開(kāi)課:算法導(dǎo)論的《MIT公開(kāi)課:線性時(shí)間排序》。

根據(jù)上面的定理,我們知道任何比較排序算法的運(yùn)行時(shí)間不會(huì)快于nlgn。那么我們是否可以突破這個(gè)限制呢?當(dāng)然可以,接下來(lái)我們將介紹三種線性時(shí)間的排序算法,它們都不是通過(guò)比較來(lái)排序的,因此,下界Ω(nlgn)對(duì)它們不適用。

二、計(jì)數(shù)排序(Counting Sort)

計(jì)數(shù)排序的基本思想就是對(duì)每一個(gè)輸入元素x,確定小于x的元素的個(gè)數(shù),這樣就可以把x直接放在它在最終輸出數(shù)組的位置上,例如:

 

算法的步驟大致如下:

①.找出待排序的數(shù)組中最大和最小的元素

②.統(tǒng)計(jì)數(shù)組中每個(gè)值為i的元素出現(xiàn)的次數(shù),存入數(shù)組C的第i項(xiàng)

③.對(duì)所有的計(jì)數(shù)累加(從C中的第一個(gè)元素開(kāi)始,每一項(xiàng)和前一項(xiàng)相加)

④.反向填充目標(biāo)數(shù)組:將每個(gè)元素i放在新數(shù)組的第C(i)項(xiàng),每放一個(gè)元素就將C(i)減去1

C++代碼如下:

/************************************************************************* 
  > File Name: CountingSort.cpp 
  > Author: SongLee 
 ************************************************************************/ 
#include<iostream> 
using namespace std; 
 
/* 
 *計(jì)數(shù)排序:A和B為待排和目標(biāo)數(shù)組,k為數(shù)組中最大值,len為數(shù)組長(zhǎng)度 
 */ 
void CountingSort(int A[], int B[], int k, int len) 
{ 
  int C[k+1]; 
  for(int i=0; i<k+1; ++i) 
    C[i] = 0; 
  for(int i=0; i<len; ++i) 
    C[A[i]] += 1; 
  for(int i=1; i<k+1; ++i) 
    C[i] = C[i] + C[i-1]; 
  for(int i=len-1; i>=0; --i) 
  { 
    B[C[A[i]]-1] = A[i]; 
    C[A[i]] -= 1; 
  } 
} 
 
/* 輸出數(shù)組 */ 
void print(int arr[], int len) 
{ 
  for(int i=0; i<len; ++i) 
    cout << arr[i] << " "; 
  cout << endl; 
} 
 
/* 測(cè)試 */ 
int main() 
{ 
  int origin[8] = {4,5,3,0,2,1,15,6}; 
  int result[8]; 
  print(origin, 8); 
  CountingSort(origin, result, 15, 8); 
  print(result, 8); 
  return 0; 
}

當(dāng)輸入的元素是0到k之間的整數(shù)時(shí),時(shí)間復(fù)雜度是O(n+k),空間復(fù)雜度也是O(n+k)。當(dāng)k不是很大并且序列比較集中時(shí),計(jì)數(shù)排序是一個(gè)很有效的排序算法。計(jì)數(shù)排序是一個(gè)穩(wěn)定的排序算法。

可能你會(huì)發(fā)現(xiàn),計(jì)數(shù)排序似乎饒了點(diǎn)彎子,比如當(dāng)我們剛剛統(tǒng)計(jì)出C,C[i]可以表示A中值為i的元素的個(gè)數(shù),此時(shí)我們直接順序地掃描C,就可以求出排序后的結(jié)果。的確是這樣,不過(guò)這種方法不再是計(jì)數(shù)排序,而是桶排序,確切地說(shuō),是桶排序的一種特殊情況。

三、桶排序(Bucket Sort)

桶排序(Bucket Sort)的思想是將數(shù)組分到有限數(shù)量的桶子里。每個(gè)桶子再個(gè)別排序(有可能再使用別的排序算法)。當(dāng)要被排序的數(shù)組內(nèi)的數(shù)值是均勻分配的時(shí)候,桶排序可以以線性時(shí)間運(yùn)行。桶排序過(guò)程動(dòng)畫(huà)演示:Bucket Sort,桶排序原理圖如下:

 

C++代碼如下:

/************************************************************************* 
  > File Name: BucketSort.cpp 
  > Author: SongLee 
 ************************************************************************/ 
#include<iostream> 
using namespace std; 
 
/* 節(jié)點(diǎn) */ 
struct node 
{ 
  int value; 
  node* next; 
}; 
 
/* 桶排序 */ 
void BucketSort(int A[], int max, int len) 
{ 
  node bucket[len]; 
  int count=0; 
  for(int i=0; i<len; ++i) 
  { 
    bucket[i].value = 0; 
    bucket[i].next = NULL; 
  } 
   
  for(int i=0; i<len; ++i) 
  { 
    node *ist = new node(); 
    ist->value = A[i]; 
    ist->next = NULL; 
    int idx = A[i]*len/(max+1); // 計(jì)算索引 
    if(bucket[idx].next == NULL) 
    { 
      bucket[idx].next = ist; 
    } 
    else /* 按大小順序插入鏈表相應(yīng)位置 */ 
    { 
      node *p = &bucket[idx]; 
      node *q = p->next; 
      while(q!=NULL && q->value <= A[i]) 
      { 
        p = q; 
        q = p->next; 
      } 
      ist->next = q; 
      p->next = ist; 
    } 
  } 
 
  for(int i=0; i<len; ++i) 
  { 
    node *p = bucket[i].next; 
    if(p == NULL) 
      continue; 
    while(p!= NULL) 
    { 
      A[count++] = p->value; 
      p = p->next; 
    } 
  } 
} 
 
/* 輸出數(shù)組 */ 
void print(int A[], int len) 
{ 
  for(int i=0; i<len; ++i) 
    cout << A[i] << " "; 
  cout << endl; 
} 
 
/* 測(cè)試 */ 
int main() 
{ 
  int row[11] = {24,37,44,12,89,93,77,61,58,3,100}; 
  print(row, 11); 
  BucketSort(row, 235, 11); 
  print(row, 11); 
  return 0; 
} 

四、基數(shù)排序(Radix Sort)

基數(shù)排序(Radix Sort)是一種非比較型排序算法,它將整數(shù)按位數(shù)切割成不同的數(shù)字,然后按每個(gè)位分別進(jìn)行排序。基數(shù)排序的方式可以采用MSD(Most significant digital)或LSD(Least significant digital),MSD是從最高有效位開(kāi)始排序,而LSD是從最低有效位開(kāi)始排序。

當(dāng)然我們可以采用MSD方式排序,按最高有效位進(jìn)行排序,將最高有效位相同的放到一堆,然后再按下一個(gè)有效位對(duì)每個(gè)堆中的數(shù)遞歸地排序,最后再將結(jié)果合并起來(lái)。但是,這樣會(huì)產(chǎn)生很多中間堆。所以,通?;鶖?shù)排序采用的是LSD方式。

LSD基數(shù)排序?qū)崿F(xiàn)的基本思路是將所有待比較數(shù)值(正整數(shù))統(tǒng)一為同樣的數(shù)位長(zhǎng)度,數(shù)位較短的數(shù)前面補(bǔ)零。然后,從最低位開(kāi)始,依次進(jìn)行一次排序。這樣從最低位排序一直到最高位排序完成以后, 數(shù)列就變成一個(gè)有序序列。需要注意的是,對(duì)每一個(gè)數(shù)位進(jìn)行排序的算法必須是穩(wěn)定的,否則就會(huì)取消前一次排序的結(jié)果。通常我們使用計(jì)數(shù)排序或者桶排序作為基數(shù)排序的輔助算法?;鶖?shù)排序過(guò)程動(dòng)畫(huà)演示:Radix Sort

C++實(shí)現(xiàn)(使用計(jì)數(shù)排序)如下:

/************************************************************************* 
  > File Name: RadixSort.cpp 
  > Author: SongLee 
 ************************************************************************/ 
#include<iostream> 
using namespace std; 
 
// 找出整數(shù)num第n位的數(shù)字 
int findIt(int num, int n) 
{ 
  int power = 1; 
  for (int i = 0; i < n; i++) 
  { 
    power *= 10; 
  } 
  return (num % power) * 10 / power; 
} 
 
// 基數(shù)排序(使用計(jì)數(shù)排序作為輔助) 
void RadixSort(int A[], int len, int k) 
{ 
  for(int i=1; i<=k; ++i) 
  { 
    int C[10] = {0};  // 計(jì)數(shù)數(shù)組 
    int B[len];    // 結(jié)果數(shù)組 
 
    for(int j=0; j<len; ++j) 
    { 
      int d = findIt(A[j], i); 
      C[d] += 1; 
    } 
 
    for(int j=1; j<10; ++j) 
      C[j] = C[j] + C[j-1]; 
 
    for(int j=len-1; j>=0; --j) 
    { 
      int d = findIt(A[j], i); 
      C[d] -= 1; 
      B[C[d]] = A[j]; 
    } 
     
    // 將B中排好序的拷貝到A中 
    for(int j=0; j<len; ++j) 
      A[j] = B[j]; 
  } 
} 
 
// 輸出數(shù)組 
void print(int A[], int len) 
{ 
  for(int i=0; i<len; ++i) 
    cout << A[i] << " "; 
  cout << endl; 
} 
 
// 測(cè)試 
int main() 
{ 
  int A[8] = {332, 653, 632, 5, 755, 433, 722, 48}; 
  print(A, 8); 
  RadixSort(A, 8, 3); 
  print(A, 8); 
  return 0; 
}

基數(shù)排序的時(shí)間復(fù)雜度是 O(k·n),其中n是排序元素個(gè)數(shù),k是數(shù)字位數(shù)。注意這不是說(shuō)這個(gè)時(shí)間復(fù)雜度一定優(yōu)于O(nlgn),因?yàn)閚可能具有比較大的系數(shù)k。

另外,基數(shù)排序不僅可以對(duì)整數(shù)排序,也可以對(duì)有多個(gè)關(guān)鍵字域的記錄進(jìn)行排序。例如,根據(jù)三個(gè)關(guān)鍵字年、月、日來(lái)對(duì)日期進(jìn)行排序。

相關(guān)文章

  • C++中的數(shù)組詳情

    C++中的數(shù)組詳情

    這篇文章主要介紹了C++中的數(shù)組,數(shù)組其實(shí)也是一種數(shù)據(jù)格式,不過(guò)是一種復(fù)合類型,它可以存儲(chǔ)多個(gè)同類型的值。使用數(shù)組可以將同類型的變量整合起來(lái)管理,下面?zhèn)z看看文章的具體舉例內(nèi)容,需要的朋友可以參考一下
    2021-11-11
  • Opencv實(shí)現(xiàn)視頻播放與進(jìn)度控制

    Opencv實(shí)現(xiàn)視頻播放與進(jìn)度控制

    這篇文章主要為大家詳細(xì)介紹了Opencv實(shí)現(xiàn)視頻播放與進(jìn)度控制,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++中strlen(),sizeof()與size()的區(qū)別

    C++中strlen(),sizeof()與size()的區(qū)別

    本文主要介紹了C++中strlen(),sizeof()與size()的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • C++ 11實(shí)現(xiàn)檢查是否存在特定的成員函數(shù)

    C++ 11實(shí)現(xiàn)檢查是否存在特定的成員函數(shù)

    C++11/14相比以往的C++98/03在很多方面做了簡(jiǎn)化和增強(qiáng),尤其是在泛型編程方面,讓C++的泛型編程的威力變得更加強(qiáng)大,下面這篇文章主要介紹了利用C++ 11實(shí)現(xiàn)檢查是否存在特定成員函數(shù)的相關(guān)資料,需要的朋友可以參考下。
    2017-02-02
  • C++語(yǔ)言編寫(xiě)寫(xiě)日志類

    C++語(yǔ)言編寫(xiě)寫(xiě)日志類

    這篇文章主要介紹了C++語(yǔ)言編寫(xiě)寫(xiě)日志類的相關(guān)資料,支持寫(xiě)日志級(jí)別設(shè)置、支持多線程、支持可變形參表寫(xiě)日志,需要的朋友可以參考下
    2015-12-12
  • c++ priority_queue用法入門(mén)超詳細(xì)教程

    c++ priority_queue用法入門(mén)超詳細(xì)教程

    priority_queue即優(yōu)先級(jí)隊(duì)列,它的使用場(chǎng)景很多,它底層是用大小根堆實(shí)現(xiàn)的,可以用log(n)的時(shí)間動(dòng)態(tài)地維護(hù)數(shù)據(jù)的有序性,這篇文章主要介紹了c++ priority_queue用法入門(mén)超詳細(xì)教程,需要的朋友可以參考下
    2023-12-12
  • C語(yǔ)言常量介紹

    C語(yǔ)言常量介紹

    這篇文章介紹了C語(yǔ)言中的常量,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • C語(yǔ)言的多級(jí)指針你了解嗎

    C語(yǔ)言的多級(jí)指針你了解嗎

    這篇文章主要介紹了C語(yǔ)言中的多級(jí)指針,本文給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能給你帶來(lái)幫助
    2021-08-08
  • Qt實(shí)現(xiàn)轉(zhuǎn)動(dòng)輪播圖

    Qt實(shí)現(xiàn)轉(zhuǎn)動(dòng)輪播圖

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)轉(zhuǎn)動(dòng)輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • 詳解C++基礎(chǔ)——類繼承

    詳解C++基礎(chǔ)——類繼承

    這篇文章主要介紹了C++類繼承,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論

临泉县| 马鞍山市| 项城市| 达日县| 太仆寺旗| 东乡县| 榆社县| 慈溪市| 永修县| 桓仁| 阜新市| 宁德市| 宁都县| 建宁县| 洪湖市| 郸城县| 新宾| 汝南县| 赣榆县| 扎赉特旗| 靖远县| 新绛县| 连平县| 绥棱县| 出国| 阳东县| 辉南县| 东方市| 樟树市| 玉屏| 广水市| 巨鹿县| 石屏县| 黑河市| 柳州市| 邳州市| 六枝特区| 木兰县| 齐齐哈尔市| 崇信县| 江源县|