国产成人精品三级麻豆,色综合天天综合高清网,亚洲精品夜夜夜,国产成人综合在线女婷五月99播放,色婷婷色综合激情国产日韩

當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > 排序與排序算法

排序與排序算法 時(shí)間:2018-09-26      來源:未知

一、排序的基本概念與分類

1、排序的定義

假設(shè)含有n個(gè)記錄的序列為{r1,r2,……rn},其相對(duì)應(yīng)的關(guān)鍵字分別為{k1,k2,……kn},需確定一種序列,使其關(guān)鍵字滿足k1<=k2<=……<=km(非遞減)或k1>=k2>=……>=km(非遞增)關(guān)系,即使得序列成為一個(gè)按關(guān)鍵字有序的序列{r1,r2,……,rm},這樣的操作就稱為排序。

排序的依據(jù)是關(guān)鍵字之間的大小關(guān)系,那么,對(duì)于同一個(gè)記錄集合,針對(duì)不同的關(guān)鍵字進(jìn)行排序,可以得到不同的序列。

2、排序的穩(wěn)定性。

假設(shè)在排序前,有ki=kj(1<=i<=n,1<=j<=n,i不等于j),且在排序前的序列中ri位置于rj(即i

例如有序列:

編號(hào) 姓名 總分

1 Li 750

2 Liu 730

3 Zhou 738

4 Han 750

此時(shí)我們按總分排序,如果得到

1 Li 750

4 Han 750

2 Zhou 738

3 Liu 730

這樣排序算法就是穩(wěn)定的。而如果得到

4 Han 750

1 Li 750

2 Zhou 738

3 Liu 730

則這樣的排序算法就是不穩(wěn)定的。

對(duì)于多個(gè)關(guān)鍵字排序時(shí),如果有一組關(guān)鍵字會(huì)得到不穩(wěn)定的結(jié)果,則我們就認(rèn)為此排序算法是不穩(wěn)定的。

3、排序算法的分類

1)按數(shù)據(jù)位置分類

根據(jù)排序過程中待排數(shù)據(jù)是否全部被放置在內(nèi)存中,排序分為:內(nèi)排序和外排序

內(nèi)排序:排序過程中,待排數(shù)據(jù)全部被放置在內(nèi)存中。

外排序:排序過程中,因記錄太多,不能同時(shí)放在內(nèi)存中,整個(gè)排序過程中需要在內(nèi)外存之間多次交換數(shù)據(jù)才能進(jìn)行。

我們這里只討論內(nèi)排序算法。對(duì)于內(nèi)排序來說,排序算法的性能主要受3個(gè)方面影響:

⒈時(shí)間性能

排序是數(shù)據(jù)處理時(shí)經(jīng)常執(zhí)行的操作,往往屬于核心代碼部分,因此排序算法的時(shí)間開銷是衡量其好壞的重要標(biāo)志。在排序中,主要涉及到兩種操作:比較與移動(dòng)。高效率的排序算法應(yīng)該是具有盡可能少的關(guān)鍵字比較次數(shù)和盡可能少的數(shù)據(jù)移動(dòng)次數(shù)。

⒉輔助空間

評(píng)價(jià)排序算法的另一個(gè)主要標(biāo)準(zhǔn)是執(zhí)行算法所需要的輔助空間。輔助存儲(chǔ)空間是除了存放待排序所占用的存儲(chǔ)空間之外,執(zhí)行算法所需要的額外存儲(chǔ)空間。

⒊算法的復(fù)雜性

過于復(fù)雜的算法會(huì)影響其排序性能。

2)按排序操作分類

根據(jù)排序過程中借助的操作,我們把排序分為:插入排序、交換排序、選擇排序和歸并排序。

3)按算法的復(fù)雜性分類

根據(jù)排序算法的復(fù)雜性分類,可分為簡單排序算法和改進(jìn)排序算法。

簡單排序算法:冒泡排序、直接選擇排序、直接插入排序

改進(jìn)排序算法:Shell排序、堆排序、歸并排序、快速排序

//注:下文中涉及到的代碼詳見附錄

二、冒泡排序

無論學(xué)習(xí)哪種編程語言,當(dāng)學(xué)習(xí)到循環(huán)與數(shù)組等概念的時(shí)候,通常會(huì)介紹一種排序算法來作為例子或練習(xí)。而這種排序算法通常都是冒泡排序。

1、簡單的冒泡排序

冒泡排序(Bubble Sort)是一種交換排序,它的基本思想是:兩兩比較相鄰記錄的關(guān)鍵字,如果反序則交換,直到?jīng)]有反序?yàn)橹埂?/p>

在排序過程中,較小的數(shù)字(或較大的數(shù)字)會(huì)如同水下的氣泡一樣慢慢浮出水面,冒泡排序的命名就此而來。

//代碼見附錄

2、冒泡排序優(yōu)化1

冒泡排序是否可以進(jìn)行優(yōu)化呢?答案是肯定的。

試想,如果待排序數(shù)據(jù)是基本有序的(例如2,1,3,4,5,6,7,8,9,10,除了第一和第二個(gè)關(guān)鍵字不同,需要交換外,其他數(shù)據(jù)關(guān)鍵字都已經(jīng)有序。此時(shí)我們只需交換這兩個(gè)數(shù)字即可,而無需將冒泡排序執(zhí)行到底。

我們可以設(shè)置一個(gè)標(biāo)志位flag,用它來指示一次冒泡排序執(zhí)行后是否有數(shù)據(jù)交換。如果一次排序后沒有數(shù)據(jù)交換,我們就可以認(rèn)為數(shù)據(jù)已經(jīng)有序,無需再繼續(xù)執(zhí)行后面的工作了。

//代碼見附錄

代碼改動(dòng)的關(guān)鍵就是在外層循環(huán)for()的結(jié)束條件中,增加了對(duì)flag是否是true的判斷。這樣的改進(jìn)能避免數(shù)據(jù)在有序的情況下做無意義的循環(huán)判斷,從而提升效率。

3、冒泡排序優(yōu)化2

從另一個(gè)角度來想,一次循環(huán)數(shù)據(jù)從前掃描到后,然后再從前掃描到后……也就是說,“磁頭”掃描一個(gè)來回移動(dòng)一個(gè)關(guān)鍵字使其有序。如果我們能在“磁頭”移動(dòng)回表頭時(shí),也能移動(dòng)一個(gè)關(guān)鍵字,那么就相當(dāng)于一次掃描一個(gè)來回移動(dòng)兩個(gè)關(guān)鍵字,可以提升其執(zhí)行效率。

//代碼見附錄

三、直接選擇排序

冒泡排序是基于比較和交換的排序,其算法思想就是不斷交換,通過交換完成終排序。而直接選擇排序則是基于選擇的排序,其算法思想是每次選出待排數(shù)據(jù)的關(guān)鍵字中大(或小)的數(shù)據(jù)作為第i個(gè)記錄。

1、直接選擇排序算法

選擇排序算法(Selection Sort)就是通過n-i次關(guān)鍵字比較,從n-i+1個(gè)數(shù)據(jù)中每次挑選出關(guān)鍵字小(或大)的數(shù)據(jù)并和第i(1<=i<=n)個(gè)數(shù)據(jù)交換之。

//代碼見附錄

注意代碼中的min是這次排序過程中小數(shù)據(jù)的下標(biāo)。

從性能上來說,選擇排序略優(yōu)于冒泡排序。

四、直接插入排序

撲克牌是我們都玩過的游戲。那么摸到手的撲克牌如何理牌呢?一般情況下,都是選出一張牌,將它放置在比它大和比它小的兩張牌之間。這里我們用于理牌的方法就是直接插入排序。

1、直接插入排序算法

直接插入排序算法(Straight Insertion Sort)的基本操作是將一個(gè)數(shù)據(jù)插入到一個(gè)已經(jīng)排好序的有序表中,從而得到一個(gè)新的有序表。重復(fù)這個(gè)過程,直至所有數(shù)據(jù)有序。

//代碼見附錄

需要注意的是,直接插入排序需要一個(gè)已經(jīng)有序的序列作為“基準(zhǔn)”。代碼中,選區(qū)r[0]與r[1]作為基準(zhǔn),在排序前,需要判斷r[0]與r[1]的關(guān)系保證其是有序表。可以嘗試省略掉這一步,觀察排序后的內(nèi)容。

從性能上來說,直接插入排序略優(yōu)于冒泡排序。

五、快速排序

上文中介紹的的冒泡排序、選擇排序、直接插入排序及其改進(jìn)版本,都屬于簡單排序算法。因?yàn)樗鼈兊臅r(shí)間復(fù)雜度都為O(n^2)。而改進(jìn)排序算法(Shell排序、堆排序、歸并排序、快速排序)的時(shí)間復(fù)雜度都為O(nlog2n)甚至更快。在這里我們主要學(xué)習(xí)快速排序。

1、快速排序算法

快速排序算法早由圖靈獎(jiǎng)獲得者Tony Hoare于1962年設(shè)計(jì)出來,被稱為“20世紀(jì)十大算法”之一。

快速排序相當(dāng)于冒泡排序的升級(jí),二者都屬于交換排序類。

快速排序(Quick Sort)的基本思想是:通過一趟排序?qū)⒋艛?shù)據(jù)分割成獨(dú)立的兩部分,其中一部分的關(guān)鍵字都比另一部分的關(guān)鍵字小。之后對(duì)這兩部分分別進(jìn)行排序,終達(dá)到整體有序。

快速排序算法的文字描述是:

1)設(shè)置兩個(gè)變量i、j,排序開始的時(shí)候:i=0,j=N-1;

2)以第一個(gè)數(shù)組元素作為關(guān)鍵數(shù)據(jù),賦值給key,即key=A[0];

3)從j開始向前搜索,即由后開始向前搜索(j--),找到第一個(gè)小于key的值A(chǔ)[j],將A[j]和A[i]互換;

4)從i開始向后搜索,即由前開始向后搜索(i++),找到第一個(gè)大于key的A[i],將A[i]和A[j]互換;

5)重復(fù)第3、4步,直到i=j;此時(shí)令循環(huán)結(jié)束。將key值賦值到i(或j)的位置。

6)遞歸操作數(shù)組A[]在key值左的左半部分。

7)遞歸操作數(shù)組A[]在key值右的右半部分。

//代碼見附錄

2、快速排序算法的優(yōu)缺點(diǎn)

快速排序算法之所以叫“快速”排序,意味著目前階段沒有人找到更優(yōu)秀于這個(gè)算法的排序算法。如果某一天有人找到了更好的排序算法,“快速”就會(huì)名不副實(shí),不過,至今為止,Tony Hoare發(fā)明的排序算法經(jīng)過多次優(yōu)化后,在整體性能上,依然是排序算法中的王者。

不過快速排序算法仍有缺陷,快速排序算法雖然對(duì)大數(shù)據(jù)排序十分擅長,但不擅長數(shù)據(jù)不多時(shí)進(jìn)行排序。在數(shù)據(jù)不多時(shí),快速排序與冒泡排序幾乎看不出時(shí)間上的優(yōu)勢,只有數(shù)據(jù)足夠大時(shí),快速排序才能發(fā)揮出它的優(yōu)勢。因此我們在對(duì)數(shù)據(jù)進(jìn)行排序時(shí),若數(shù)據(jù)量不太多,可以選擇使用三種簡單排序算法(冒泡排序、選擇排序、直接插入排序);若數(shù)據(jù)量巨大,我們就需要選擇快速排序。

附錄1:各排序算法代碼實(shí)現(xiàn)(C語言)

#include

#include

#define MAXSIZE 10

typedef struct

{

int r[MAXSIZE];//存儲(chǔ)待排序數(shù)據(jù)

int length;//記錄順序表的長度

}Sqlist;

void swap(Sqlist *L,int i,int j)//交換數(shù)據(jù)函數(shù)

{

int temp = L->r[i];

L->r[i] = L->r[j];

L->r[j] = temp;

}

void print(Sqlist *L)//打印數(shù)據(jù)函數(shù)

{

int i;

for(i=0;ilength;i++)

printf("%d ",L->r[i]);

printf("\n");

}

void BubbleSort(Sqlist *L)//冒泡排序

{

int i,j;

for(i=0;ilength;i++)

{

for(j=L->length-1;j>=i;j--)

{

if(L->r[j]>L->r[j+1])

swap(L,j,j+1);

}

}

}

void BubbleSort2(Sqlist *L)//冒泡排序改進(jìn)版1:增加標(biāo)志位

{

int i,j;

int flag = 1;

for(i=0;ilength && flag;i++)

{

flag = 0;

for(j=L->length-1;j>=i;j--)

{

if(L->r[j]>L->r[j+1])

{

swap(L,j,j+1);

flag = 1;

}

}

}

}

void BubbleSort3(Sqlist *L)//冒泡排序改進(jìn)版2:雙向移動(dòng)數(shù)據(jù)(雞尾酒排序)

{

int i,j;

for(i=0;ilength/2;i++)

{

for(j=i;jlength-i-1;j++)

{

if(L->r[j]>L->r[j+1])

swap(L,j,j+1);

}

for(j=L->length-1-(i+1);j>i;j--)

{

if(L->r[j]r[j-1])

swap(L,j-1,j);

}

}

}

void SelectSort(Sqlist *L)//直接選擇排序

{

int i,j,min;//min是當(dāng)次循環(huán)的小值的下標(biāo)

for(i=0;ilength;i++)

{

min=i;

for(j=i+1;j<=L->length;j++)

{

if(L->r[min]>L->r[j])

min=j;

}

if(i!=min)

swap(L,i,min);

}

}

void InsertSort(Sqlist *L)//直接插入排序

{

int i,j,tmp;

if(L->r[0]>L->r[1])//首先保證前2個(gè)元素有序,這樣后續(xù)元素才能插入

swap(L,0,1);

for(i=2;i<=L->length;i++)//插入L->r[i]元素

{

if(L->r[i]r[i-1])

{

tmp=L->r[i];

for(j=i-1;L->r[j]>tmp;j--)//將所有大于L->r[i]元素都后移,空出位置

L->r[j+1]=L->r[j];

L->r[j+1]=tmp;//插入正確位置

}

}

}

void QSort1(Sqlist *L,int left,int right)//快速排序

{

int i=left,j=right;

if(left>=right)

return;

int key = L->r[left];

while(i

{

while(L->r[j]>=key && i

j--;

L->r[i]=L->r[j];

while(L->r[i]<=key && i

i++;

L->r[j]=L->r[i];

}

L->r[i]=key;

QSort1(L,left,i-1);

QSort1(L,i+1,right);

}

/*快速排序算法第二種寫法*/

int Partition(Sqlist *L,int low,int high)

{

int pivotkey,tmp;

pivotkey=L->r[low];

tmp=pivotkey;

while(low

{

while(lowr[high]>=pivotkey)

high--;

L->r[low]=L->r[high];

while(lowr[low]<=pivotkey)

low++;

L->r[high]=L->r[low];

}

L->r[low]=tmp;

return low;

}

void QSort2(Sqlist *L,int low,int high)

{

int pivot;

if(low

{

pivot = Partition(L,low,high);

QSort2(L,low,pivot-1);

QSort2(L,pivot+1,high);

}

}

/*快速排序算法第二種寫法end*/

int main()

{

Sqlist data;

data.r[0]=9;data.r[1]=1;data.r[2]=5;data.r[3]=8;data.r[4]=3;data.r[5]=7;data.r[6]=4;data.r[7]=6;data.r[8]=2;data.r[9]=10;

data.length=sizeof(data.r)/sizeof(data.r[0]);

//BubbleSort(&data);

//BubbleSort2(&data);

//BubbleSort3(&data);

//SelectSort(&data);

//InsertSort(&data);

//QSort1(&data,0,data.length-1);

//QSort2(&data,0,data.length-1);

print(&data);

return 0;

}

附錄2:各排序算法時(shí)間復(fù)雜度與空間復(fù)雜度對(duì)比

上一篇:師兄碼字2000談在華清學(xué)習(xí)的感受

下一篇:動(dòng)態(tài)庫和靜態(tài)庫的區(qū)別

熱點(diǎn)文章推薦
華清學(xué)員就業(yè)榜單
高薪學(xué)員經(jīng)驗(yàn)分享
熱點(diǎn)新聞推薦
前臺(tái)專線:010-82525158 企業(yè)培訓(xùn)洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠(yuǎn)見科技集團(tuán)有限公司 版權(quán)所有 ,京ICP備16055225號(hào)-5,京公海網(wǎng)安備11010802025203號(hào)

回到頂部