資料結構內排序之慘死攻略(二)
阿新 • • 發佈:2019-01-10
聽聞今天還要學資料結構,心中堵著一片烏雲。
就算受低潮情緒影響也要堅持學下去啊。
目錄
5 歸併排序
簡化下高考一本,二本,專科分數線的劃分方式
5.1 栗子
- 劃分為兩個子序列
- 分別對每個子序列歸併排序
- 有序子序列合併
5.2 程式碼實現
template<class Record> void MergeSort(Record Array[],Record TempArray[],int left,int right){ //Array為待排序陣列,left,right兩端 int middle; if(left < right){//序列中只有0或1個記錄,不用排序 middle = (left + right)/2; //平分為兩個子序列 //對左邊一半進行遞迴 MergeSort(Array,TempArray,left,middle); //對右邊一半進行遞迴 MergeSort(Array,TempArray,middle+1,right); Merge(Array,TempArray,left,right,middle);//歸併 } }
歸併函式
//兩個有序子序列都從左向右掃描,歸併到新陣列 template<class Record> void Merge(Record Array[],Record TempArray[],int left,int right,int middle){ int i,j,index1,index2; //將陣列暫存入臨時陣列 for(j=left;j<=right;j++) TempArray[j] = Array[j]; index1 = left; //左邊子序列的起始位置 index2 = middle + 1; //右邊子序列的起始位置 i = left; //從左開始歸併 while(index1 <= middle && index2 <= right){ //取較小者插入合併陣列中 if(TempArray[index1] <= TempArray[index2]) Array[i++] = TempArray[index1++]; else Array[i++] = TempArray[index2++]; } while(index1 <= middle) //只剩左序列,可直接複製 Array[i++] = TempArray[index1++]; while(index2 <= right) //與上個迴圈互斥,複製右序列 Array[i++] = TempArray[index2++]; }
5.3 歸併演算法優化
- 對基本已排序的序列進行直接插入排序,小序列不遞迴
- R.Sedgewick優化:拆分方式不變,歸併時從兩端開始處理,向中間推進,簡化邊界判斷
5.3.1 R.Sedgewick優化
優化前
優化後
還是看不懂?沒事,接著解析。先對左邊子序列進行歸併
歸併時應該為
此時對右邊子序列32,45進行倒置
接著
對右邊子序列進行歸併
對右邊的子序列34',64進行倒置
........剩下步驟同上,最終為12 34’ 64 78
繼續合併
右邊子序列進行倒置
.......最終
5.3.2 R.Sedgewick程式碼實現
template<class Record>
void ModMergeSort(Record Array[],Record TempArray[],int left,int right){
//Array為待排序陣列,left,right指向兩端
int middle;
if(right-left+1 > THRESHOLD){//長序列遞迴,threshold閾值,臨界點
middle = (left + right)/2;
ModMergeSort(Array,TempArray,left,middle);//左
ModMergeSort(Array,TempArray,middle+1,right);//右
//對相鄰的有序序列進行歸併
ModMerge(Array,TempArray,left,right,middle);//歸併
}
else InsertSort(&Array[left],right-left+1);//小序列插入排序
}
優化的歸併函式
template<class Record> void ModMerge(
Record Array[],Record TempArray[],int left,int right,int middle){
int index1,index2//兩個子序列的起始位置
int i,j,k;
for(i = left; i <= middle; i++)
TempArray[i] = Array[i]; //複製左邊的子序列
for(j = 1; j <= right-middle; j++) //顛倒複製右序列
TempArray[right-j+1] = Array[j+middle];
for(index=left,index2=right,k=left; k<=right; k++)
if(TempArray[index1] <= TempArray[index2])
Array[k] = TempArray[index1++];
else
Array[k] = TempArray[index2--];
}
5.4 演算法分析
漫畫亂入,自娛自樂。
6 分配排序和索引排序
- 不需要進行記錄間的兩兩比較
- 需要事先知道記錄序列的一些具體情況,關鍵碼的分佈
6.1 桶式排序
- 事先知道序列中的記錄都位於某個小區間段[0,m]內
- 將具有相同值的記錄都分配到同一個桶中,再依次按照編號從桶中取出記錄,組成一個有序序列
6.1.1 栗子
6.1.2 程式碼實現
template<class Record> void BucketSort(Record Array[],int n,int max){
Record *TempArray = new Record[n]; //臨時陣列
int *count = new int[max]; //桶容量計數器
int i;
for(i=0; i<n; i++) //把序列複製到臨時陣列
TempArray[i] = [i];
for(i=0; i<max; i++) //所有計數器初始置為0
count[i] = 0;
for(i=0; i<n; i++) //統計每個取值出現的次數
count[Array[i]]++;
for(i=0; i<max; i++) //統計小於等於i的元素的個數
count[i] = count[i-1] + count[i]; //c[i]記錄i+1的起址
for(i=n-1; i>=0; i--) //區域性開始,保證穩定性
Array[--count][TempArray[i]] = TempArray[i];
}
6.1.3 演算法分析
6.2 基數排序
桶式排序只適合m很小的情況。
基數排序:當m很大時,可以將一個記錄的值分為多個部分來比較。
還是直接看例子吧,概念神馬的先再見。
6.2.1 栗子1
6.2.2 栗子2
6.2.3 LSD(低位優先)-基於順序儲存
原始輸入陣列 R 的長度為 n,基數為 r,排序碼個數為 d
程式碼實現
template <class Record>
void RadixSort(Record Array[], int n, int d, int r) {
Record *TempArray = new Record[n];
int *count = new int[r];
int i, j, k;
int Radix = 1; // 模進位,用於取Array[j]的第i位
for (i = 1; i <= d; i++) {
// 對第 i 個排序碼分配
for (j = 0; j < r; j++)
count[j] = 0; // 初始計數器均為0
for (j = 0; j < n; j++) { // 統計每桶記錄數
k = (Array[j] / Radix) % r; // 取第i位
count[k]++; // 相應計數器加1
}
for (j = 1; j < r; j++) // 給桶劃分下標界
count[j] = count[j-1] + count[j];
for (j = n-1; j >= 0; j--) { // 從陣列尾部收集
k = (Array[j] / Radix ) % r; // 取第 i 位
count[k]--; // 桶剩餘量計數器減1
TempArray[count[k]] = Array[j]; // 入桶
}
for (j = 0; j < n; j++) // 內容複製回
Array 中 Array[j] = TempArray[j];
Radix *= r; // 修改模Radix
}
}
演算法分析
6.2.4 LSD(低位優先)-基於鏈式儲存
原始輸入陣列 R 的長度為 n,基數為 r,排序碼個數為 d
鏈式儲存避免了空間浪費情況
程式碼實現(後續補)
演算法分析
7 總結
4) 元素的移動次數與關鍵字的初始排列次序無關:基數排序
元素的移動次數與關鍵字的初始排列次序有關:直接插入排序,氣泡排序,快速排序
5) 快速排序每一躺結束後都將至少一個元素放在最終位置。
內排序暫時告一段落了,然而仙氣已經耗竭。
學習自:
張銘《資料結構》
程傑《大話資料結構》
陳越,何欽銘《資料結構》
附加:排序演算法的舞蹈
氣泡排序:http://t.cn/hrf58M
希爾排序:http://t.cn/hrosvb,
選擇排序:http://t.cn/hros6e
插入排序:http://t.cn/hros0W
快速排序:http://t.cn/ScTA1d
歸併排序:http://t.cn/Sc1cGZ