簡介:
有許多的關於資料計算的應用程式中都用到演算法。甚至在我們開始運算資料之前,演算法的重要性就浮在我們眼前了。比如,我們在查詢**上的人時,必須按從高到低的順序。我們必須給業績最好的員工最好的獎金,這就要求我們必須從高到低,或從大到小的順序排列事物。
比如,我們查詢資料庫時,排序時,要加上
order by
語句。我們尋找手機上的某本書時,必須從已經排好序的佇列中找。如果你想高效的用二分查詢法從陣列中查詢某個元素,你可能得排序好整個陣列。有個問題要求我們必須以字典順序返回結果時,那麼我們想到要排序。
一般考慮:
假設有一種人,分給他們每人一副大亂順序的撲克,要求他們按從大到小排序。一些人可能按樁的結構排,一些人還可能把牌都放在桌子上排好序,還有一些人可能在手中就排好序了。但他們所用的時間可能不一樣。可能會出現很多樣的排序方式。
在我們排序時,我們必須有幾件事要考慮,首先就是時間。
另乙個考慮的問題就是所用到的記憶體空間。
另一點要考慮的就是穩定性。
氣泡排序:
首先我們想到的就是氣泡排序,他的時間複雜度為o(n
²),但他要求的記憶體空間也很低。
for (int i = 0; i < data.length; i++)
for (int j = 0; j < data.length - 1; j++)
if (data[j] > data[j + 1])
插入排序:
每次將乙個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子檔案中的適當位置,直到全部記錄插入完成為止。
for (int i = 0; i <= data.length; i++)
比如有這麼一組資料,插入排序的過程為:
插入排序的優點就是我們只考慮要插入的元素。待排序元素已從小到大排好序(正序)或接近排好序時,所用的比較次數和移動次數較少。
歸併排序:
遞迴的歸併排序:思想就是把要排序的陣列分成
2部分,並且單獨的對他們進行排序,然後比較這
2個陣列裡的第乙個元素,把小的那個元素從此陣列裡刪除新增到結果陣列裡。
int mergesort (int data) else if (rptr == right.length) else if (left[lptr] < right[rptr]) else
dptr++;
}return result;
}沒一次遞迴所用的時間複雜度為
0(n),
總共進行了
0(log n)
次,因此時間複雜度為
0(n * log n)
堆排序在堆排序中,我們創造乙個堆的資料結構,它就像一棵樹一樣,最小的元素始終在根節點上。執行堆排序時,所以的元素必須都插入到堆中,然後把根節點從堆移到結果陣列中。
/*ary是儲存記錄的陣列, start是需要調整為大頂堆的根記錄下標, end是
它的最後乙個葉子記錄的下標。
注意,傳入的start到end之間的記錄,除去根記錄,根記錄的左右子二叉樹都
是大頂堆,要完全符合大頂堆的性質呼叫此函式才有效。
下面函式要做的就是調整以start為根記錄,end為最後乙個葉子記錄的完全二叉樹為大頂堆。
*/void heapify(int ary, unsigned int start, unsigned int end)
else
}/* 現在max中是儲存了左右子記錄中(假設存在)關鍵字值最大的下標 */
if (ary[start] < ary[max])
else
left = start * 2;
right = start * 2 + 1;
}/* 調整到最二叉樹的最後乙個葉子結點上,二叉樹也符合大頂堆性質, 調整結束 */
}/* 進行堆排序,完成後ary中的記錄下標從1到size,它們的關鍵字值是非遞減的 */
void heapsort(int ary, unsigned int size)}/*
調整整棵二叉樹(完全無序狀態)使之成為大頂堆。
策略:首先這課二叉樹的結構是完全二叉樹,我們可以從最後乙個非葉子記錄調整,
直到整棵二叉樹的根記錄。
比如二叉樹有size個結點記錄,那麼最後乙個非葉子結點的下標就
是size / 2(取整),我們就從size / 2, size / 2 - 1, ... ,
直到調整以1為下標的整棵二叉樹為大頂堆。
因為以最後乙個葉子記錄為根的二叉樹必定符合呼叫函式heapify的條件,
位於同一層的非葉子結點必定也符合呼叫條件,heapify函式處理完後這一層後,
上一層的非葉子記錄對應的二叉樹也符合了呼叫條件,
這樣直到以整棵二叉樹的根(即ary)記錄為根的二叉樹也符合大頂堆的性質,
整個大頂堆就建立起來。
現在整棵二叉樹的根記錄就是該記錄集中關鍵字值最大的記錄。
*/void buildheap(int ary, unsigned int size)}/*
演算法分析:
1.堆排序的時間,主要由建立初始堆和反覆重建堆這兩部分的時間開銷構成,
它們均是通過呼叫heapify實現的。
堆排序的最壞時間複雜度為o(n * lgn)。堆排序的平均效能較接近於最壞效能。
buildheap最壞情況下時間複雜度為o(n),但是for迴圈在最壞情況下卻
要o(n * lgn)的時間。
2.由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的檔案。
3.堆排序是就地排序,輔助空間為o(1)。
4.它是不穩定的排序方法。
*/堆排序的時間複雜度為o(n
* log
n).
源文件
快速排序
快速排序像哈夫曼樹類似,首先把排序的陣列分成
2部分,使前部分小於關鍵字,後部分大於關鍵字。然後遞迴排序
void quicksort(seqlist r,int low,int high)
} //quicksort
int partition(seqlist r,int i,int j)
//endwhile
r[i]=pivot
; //基準記錄已被最後定位
return i;
} //partition
源文件
快速排序的最壞時間複雜度應為0(n2),最好時間複雜度為o(nlgn)。
基樹排序
基數排序是非比較排序演算法
,演算法的時間複雜度是
o(n).
相比於快速排序的
o(nlgn),
從表面上看具有不小的優勢
.但事實上可能有些出入
,因為基數排序的
n可能具有比較大的係數
k.因此在具體的應用中
,應首先對這個排序函式的效率進行評估.
基數排序的主要思路是
,將所有待比較數值(注意
,必須是正整數
)統一為同樣的數字長度
,數字較短的數前面補零
. 然後
, 從最低位開始
, 依次進行一次
穩定排序
(blog
介紹的計數排序演算法
, 因為
每個位可能的取值範圍是固定的從0到
9).這樣從最低位排序一直到最高位排序完成以後
, 數列就變成乙個有序序列.
比如這樣乙個數列排序
: 342 58 576 356,
以下描述演示了具體的排序過程
(紅色字型表示正在排序的數字)
第一次排序(個位
): 3 4 2
5 7 6
3 5 6
0 5 8
第二次排序(十位
): 3 4
2 3 5
6 0 5
8 5 7
6 第三次排序(百位
): 05 8 3
4 2
35 6 5
7 6
結果: 58 342 356 576
源文件
源文件
排序演算法 排序演算法彙總
排序演算法無疑是學習資料結構中的重點內容,本文將給出排序演算法的彙總。下面是具體的實現 include include include define n 1000000 int array n int temp n 1 氣泡排序 void bubblesort int a,int n if tag ...
排序演算法 排序演算法彙總
排序演算法無疑是學習資料結構中的重點內容,本文將給出排序演算法的彙總。下面是具體的實現 include include include define n 1000000 int array n int temp n 1 氣泡排序 void bubblesort int a,int n if tag ...
排序演算法 排序演算法彙總
排序演算法無疑是學習資料結構中的重點內容,本文將給出排序演算法的彙總。下面是具體的實現 include include include define n 1000000 int array n int temp n 1 氣泡排序 void bubblesort int a,int n if tag ...