排序演算法的深入分析和實現

2021-09-19 07:47:28 字數 4163 閱讀 9971

1.1 排序的定義

對一串行物件根據某個關鍵字進行排序。

1.2 術語說明

穩定:如果a原本在b前面,而a=b,排序之後a仍然在b的前面;

不穩定:如果a原本在b的前面,而a=b,排序之後a可能會出現在b的後面;

內排序in-place:所有排序操作都在記憶體中完成;

外排序out-place:由於資料太大,因此把資料放在磁碟中,而排序通過磁碟和記憶體的資料傳輸才能進行;

1.3 演算法總結

1、氣泡排序(bubble sort)

相鄰兩個元素比較大小,一次外迴圈比較(n-1)次;

如跑完第一次迴圈,最大的元素被移到最後一位;

內迴圈跑(n-i)次,因為最後i個元素已排好序;

時間複雜度分析

比較次數:不管怎樣,氣泡排序都要比較(n+(n-1)+…+2+1)次,即n(n-1)/2 ,o(n^2);

交換次數:有序不需要交換,逆序交換n(n-1)/2次;o(n^2);

穩定性分析:

相鄰兩元素大小一樣,自然不會多此一舉去交換,因此穩定;

c++**實現:

//氣泡排序

void

bubble_sort

(int

*a,int n)}}

}

2、選擇排序(select sort)每次選擇第i小的元素,把它放在index為i的位置上;

一共n次外迴圈,第一次選出最小元素,放在第乙個;第i次選出第i小的元素;

每次內迴圈要比較(n-i)次,最終選出後(n-i)個元素中最小的,放到i位置上。

時間複雜度分析

比較次數:選擇排序同樣比較(n+(n-1)+…+2+1)次,即n(n-1)/2 ,o(n^2);

交換次數:有序不需要交換,逆序交換n(n-1)/2次;o(n^2);

穩定性分析:

因為涉及相隔較遠的元素交換位置!

例如3 2 3 1,第一次迴圈結束,3和1交換,破壞了穩定。顯然選擇排序是不穩定。

c++**實現:

//選擇排序

void

select_sort

(int

*a,int n)

} a[index]

= a[i]

; a[i]

= min;

}}

3、插入排序(insert sort)模擬平時打牌時插牌,拿到新元素,把它放到已排好序的元素中的適當位置;

外迴圈n次,第i次外迴圈結束,則前i個數已排好序,第乙個預設排好序;

內迴圈為執行(n-i)次,將新元素和前i個排好序的依次比較,是乙個不斷往前插的過程;

時間複雜度分析

比較次數:同o(n^2);

交換次數:有序不需要交換,逆序交換n(n-1)/2次;o(n^2);

穩定性分析:

插入排序是穩定的;例如 1 2 3 3,前三個已經排好序,最後的3顯然不會再往前插;

c++**實現:

//插入排序

void

insert_sort

(int

*a,int n)}}

}

4、歸併排序(merge sort)採用分治法,將序列分成兩個n/2長度的子串行,合併時依次按大小輸出到新序列;

占用額外空間,非原址排序;

時間複雜度分析

每次遞迴複雜度o(n),遞迴層數o(lgn),所以複雜度為o(nlgn);

穩定性分析:

歸併排序是穩定的,合併過程左右兩個序列的比較大小保證了這種穩定性;

c++**實現:

//歸併排序

void

merge

(int

*a,int

*b,int p,

int r,

int q)

//此時左、右序列可能有乙個未寫完

while

(i<=r)

b[write++

]= a[i++];

while

(j<=q)

b[write++

]= a[j++];

for(

int k=p; k<=q; k++

) a[k]

= b[k];}

void

merge_sort

(int

*a,int

*b,int beg,

int end)

if(end-beg ==1)

return;}

merge_sort

(a,b,beg,

(beg+end)/2

);merge_sort

(a,b,

(beg+end)/2

+1,end)

;merge

(a,b,beg,

(beg+end)/2

,end)

;}

5、快速排序(quick sort)從數列中挑出乙個元素,稱為 「基準」(pivot);

重新排序數列,所有比pivot小的擺放在基準前面,所有比pivot大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;

遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;

partition操作實現:

pivot選擇末尾元素,維護i和j,i指向頭,j指向pivot前乙個。i不斷往後搜尋直到找到第乙個大於pivot的元素;j不斷往前搜尋直到找到第乙個小於pivot的元素。i,j都找到時交換i,j上的元素,如果j穩定性分析:

快速排序是不穩定的;

因為間隔元素的交換,很可能打破原有相同元素的順序關係;

例如3 3 1 1 2,選擇2為pivot,那麼第一次迴圈,3和1就發生了交換,打亂了穩定性;

c++**實現:

//快速排序

intpartition

(int

*a,int p,

int q)

while

(a[j]

>a[pivot]

&& j>=p )

if(i

}//交換i和pivot

int tmp = a[i]

; a[i]

= a[pivot]

; a[pivot]

= tmp;

return i;

//partition結束,滿足左邊<=它,右邊》它

}void

quick_sort

(int

*a,int beg,

int end)

深入分析python 排序

排序是每個開發人員都需要掌握的技能。排序是對程式本身有乙個全面的理解。不同的排序演算法很好地展示了演算法設計上如何強烈的影響程式的複雜度 執行速度和效率。今天的文章和談談大家都熟悉的各種排序使用 python 如何實現,廢話就不多說啦,開幹!選擇排序 選擇排序一般是將初始值設為初始值,再迴圈後面每個...

malloc和new的深入分析

1.malloc 函式 1.1 malloc的全稱是memory allocation,中文叫動態記憶體分配。原型 extern void malloc unsigned int num bytes 說明 分配長度為num bytes位元組的記憶體塊。如果分配成功則返回指向被分配記憶體的指標,分配失...

深入分析 和equals的區別

和equals是非常常見的面試題。共同點 都可以做比較,返回值都是boolean 區別 1.是比較運算子,即可以比較的基本資料型別,也可以比較引用資料型別。基本資料型別比較的是值,引用資料型別比較的是記憶體位址值 2.equals方法只能比較的是引用資料型別,equals方法在沒有重寫是比較的是位址...