数据结构与算法(一)——排序
雖然之前學(xué)過(guò)數(shù)據(jù)結(jié)構(gòu),但是已時(shí)隔四年,大概四月份復(fù)習(xí)了一遍,但是很多概念也是一知半解,所以重新整理知識(shí)點(diǎn)和運(yùn)行代碼的方式來(lái)鞏固知識(shí)。
引言
排序:是計(jì)算機(jī)程序設(shè)計(jì)中的一種重要操作,功能是將一個(gè)數(shù)據(jù)元素的任意序列重新排列成一個(gè)按關(guān)鍵字的有序序列。
根據(jù)待排序記錄的存儲(chǔ)器的不同可分為
各個(gè)排序算法的性能比較
冒泡排序
算法說(shuō)明
冒泡排序是一種交換排序。那什么是交換排序呢?
交換排序:兩兩比較待排序的關(guān)鍵字,并交換不滿足次序要求的那對(duì)數(shù),直到整個(gè)表都滿足次序要求為止。
基本思想:通過(guò)相鄰記錄兩兩比較交換的方式,找到每次迭代中數(shù)據(jù)的最大值,最終達(dá)到排序的目的。
算法描述:
- 首先將第一個(gè)記錄的關(guān)鍵字與第二個(gè)記錄的關(guān)鍵字進(jìn)行比較,若為逆序(L.r[1].key>L.r[2].key),則將兩個(gè)記錄交換,然后比較第二個(gè)記錄和第三個(gè)記錄的關(guān)鍵字,依次類推,直到第n-1個(gè)記錄和第n個(gè)記錄進(jìn)行比較為止。這是一趟排序。
- 然后進(jìn)行第二趟排序,對(duì)前n-1個(gè)記錄進(jìn)行同樣的操作。重復(fù)這樣的操作。
- 直到冒泡排序在一趟拍訊中沒有進(jìn)行過(guò)交換記錄的操作為止。
這個(gè)算法的名字由來(lái)是因?yàn)樵叫〉脑貢?huì)經(jīng)由交換慢慢“浮”到數(shù)列的頂端,故名。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = BubbleSort($list); print_r($res); function BubbleSort($list) { $len = count($list); for ($i = 0; $i < $len; $i++) { for ($j = $len-1; $j > $i; $j--) { if ($list[$j-1] > $list[$j]) { swap($list, $j-1, $j); $bChange = true; } } } echo $k; return $list; } function swap(&$list, $i, $j) { $temp = $list[$i]; $list[$i] = $list[$j]; $list[$j] = $temp; } ?> |
輸出:
| 1 2 3 4 5 6 7 8 9 10 11 | Array ( [0] => 13 [1] => 27 [2] => 38 [3] => 49 [4] => 49 [5] => 65 [6] => 76 [7] => 97 ) |
快速排序
算法說(shuō)明
快速排序是冒泡排序的改進(jìn),整個(gè)快速排序的過(guò)程是一個(gè)遞歸的過(guò)程。
基本思想:通過(guò)一趟排序?qū)⒋庞涗浄指畛瑟?dú)立兩部分,其中一部分記錄的關(guān)鍵字均比另一部分記錄的關(guān)鍵字小,則可分別對(duì)著兩部分記錄繼續(xù)記性排序,以達(dá)到整個(gè)序列有序。
算法描述:
- 一趟快速排序的步驟:
- 設(shè)兩個(gè)指針low和high,設(shè)樞軸記錄的關(guān)鍵字為pivotkey;
- 先從high所指向的位置向前搜索找到第一個(gè)小于pivotkey的記錄和樞軸記錄互相交換;
- 然后從low所指向的位置向后搜索找到第一個(gè)大于pivotkey的記錄和樞軸記錄互相交換;
- 重復(fù)前面兩步驟,知道low=high為止。
- 取當(dāng)前的pivotkey記錄所在的位置(樞軸位置),將整個(gè)記錄分割為兩個(gè)子序列,分別進(jìn)行快速排序;
- 直到待排序列中只有一個(gè)記錄為止。
用例說(shuō)明
代碼實(shí)現(xiàn)
先將樞軸記錄暫存在r[0]的位置上,排序過(guò)程只作r[row]或者r[high]的單向移動(dòng),知道一趟排序結(jié)束后,再將樞軸記錄移至正確的位置上。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include<iostream> using namespace std; // 聲明快排函數(shù) void quickSort(int a[],int,int); int main() { int array[]={34,65,12,43,67,5,78,10,3,70},k; int len=sizeof(array)/sizeof(int); cout<<"The orginal arrayare:"<<endl; for(k=0;k<len;k++) cout<<array[k]<<","; cout<<endl; quickSort(array,0,len-1); cout<<"The sorted arrayare:"<<endl; for(k=0;k<len;k++) cout<<array[k]<<","; cout<<endl; system("pause"); return 0; } void quickSort(int s[], int l, int r) { if (l< r) { int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j]>= x) // 從右向左找第一個(gè)小于x的數(shù) j--; if(i < j) s[i++] = s[j]; while(i < j && s[i]< x) // 從左向右找第一個(gè)大于等于x的數(shù) i++; if(i < j) s[j--] = s[i]; } s[i] = x; quickSort(s, l, i - 1); // 遞歸調(diào)用 quickSort(s, i + 1, r); } } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49);//這個(gè)用例輸出的是null //$list = array(9, 1, 5, 8, 3, 7, 4, 6, 2);//這個(gè)用例測(cè)試結(jié)果是對(duì)的 $res = QuickSort($list); print_r($res); print_r($list); function QuickSort($list) { $len = count($list); Qsort($list, 0, $len-1); return $list; } function Qsort(&$list, $low, $high) { if ($low < $high) { $pivot = Partition($list, $low, $high); Qsort($list, $low, $pivot-1); Qsort($list, $pivot+1, $high); } } function Partition(&$list, $low, $high) { $pvalue = $list[$low]; while ($low < $high) { while ($low < $high && $list[$high] > $pvalue) { $high--; } swap($list, $low, $high); while ($low < $high && $list[$low] < $pvalue) { $low++; } swap($list, $low, $high); } return $low; } function swap(&$list, $i, $j) { $temp = $list[$i]; $list[$i] = $list[$j]; $list[$j] = $temp; } ?> |
直接插入排序
算法說(shuō)明
直接插入排序是一種最簡(jiǎn)單的排序方法,它的基本操作是將一個(gè)記錄儀插入到已排好序的有序表中,從而得到一個(gè)新的、記錄數(shù)增1的有序表。
算法描述:
- 先取代排序序列中的第一個(gè)記錄作為一個(gè)有序序列;
- 取第二個(gè)記錄,在這個(gè)有序序列依次查找比它小的最大關(guān)鍵字,將該記錄插入到查找的關(guān)鍵字位置后面;
- 取第i個(gè)記錄按同種方法插入到當(dāng)前有序序列;
- 將最后一個(gè)記錄插入,即可完成排序。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = InsertionSort($list); print_r($res); function InsertionSort($list){ $len = count($list); for ($i = 1; $i < $len; $i++) { if ($list[$i] < $list[$i-1]) { $target = $list[$i]; for($j = $i-1; $j >= 0 && $list[$j] >= $target; $j--) { $list[$j+1] = $list[$j]; } $list[$j+1] = $target; } } return $list; } ?> |
希爾排序
算法說(shuō)明
希爾排序又稱“縮小增量排序”,也屬于插入排序類方法,但時(shí)間效率更高。希爾排序的一個(gè)特點(diǎn):子序列的構(gòu)成不是簡(jiǎn)單地“逐段分割”,而是將相隔某個(gè)“增量”的記錄組成一個(gè)子序列。
算法描述:
- 將整個(gè)待排序序列分割成若干個(gè)子序列
- 對(duì)每個(gè)子序列分別進(jìn)行直接插入排序
- 待每個(gè)子序列中的記錄有序時(shí),再縮小增量重新分割子序列,重復(fù)上一步操作,直到增量為1,進(jìn)行最后一次排序后即完成排序。
這個(gè)算法,主要是通過(guò)增量劃分子序列,使序列基本有序,減小插入排序的復(fù)雜度。
需注意的是,到目前為止,尚未有人求得一種最好的增量序列,但是也有一些局部結(jié)論。增量序列可以用多種取法,但需注意:應(yīng)使增量序列中的值沒有除1以外的公因數(shù),并且最后一個(gè)增量值必須等于1。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = ShellSort($list); print_r($res); function ShellSort($list) { $len = count($list); $increment = $len; do { $increment = floor($increment/3) + 1; for ($i = $increment; $i < $len; $i++) { if ($list[$i] < $list[$i-$increment]) { $target = $list[$i]; for ($j = $i-$increment; $j >= 0 && $list[$j] > $target; $j -= $increment) { $list[$j+$increment] = $list[$j]; } $list[$j+$increment] = $target; } } }while($increment > 1); return $list; } ?> |
簡(jiǎn)單選擇排序
算法說(shuō)明
簡(jiǎn)單選擇排序是一種選擇排序。每一趟在n-i+1(i=1,2,…,n-1)個(gè)記錄中選擇關(guān)鍵字最小的記錄作為有序序列的第i個(gè)記錄。
算法描述
- 先從n個(gè)記錄(待排序列)中找到最小的關(guān)鍵字,作為第一個(gè)記錄
- 隨后在剩下的n-1(n-i+1)子序列中再尋找最小關(guān)鍵字,作為第2(i)個(gè)記錄
- 依次類推,直到剩下最后的一個(gè)記錄(即最大關(guān)鍵字)為止。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = SelectionSort($list); print_r($res); function SelectionSort($list) { $len = count($list); for ($i = 0; $i < $len; $i++) { $min = $i; for ($j = $i; $j < $len; $j++) { if ($list[$min] > $list[$j]) { $min = $j; } } if ($min != $i) { swap($list, $min, $i); } } return $list; } function swap(&$list, $i, $j) { $temp = $list[$i]; $list[$i] = $list[$j]; $list[$j] = $temp; } ?> |
樹形選擇排序
算法說(shuō)明
樹形選擇排序,又稱“錦標(biāo)賽排序”,是一種按照錦標(biāo)賽的思想進(jìn)行選擇排序的方法,是對(duì)簡(jiǎn)單選擇排序的一種改進(jìn)。
算法描述
- 首先對(duì)n個(gè)記錄的關(guān)鍵字進(jìn)行兩兩比較,選出較小者
- 然后在其[n/2]個(gè)較小者之間再進(jìn)行兩兩比較,再選出較小者
- 如此重復(fù),知道選出最小關(guān)鍵字的記錄為止
- 將最小關(guān)鍵字輸出,然后根據(jù)關(guān)系的可傳遞性,選出次小關(guān)鍵字,依次輸出,直到輸出所有的記錄。
用例說(shuō)明
堆排序
堆:一棵順序存儲(chǔ)的完全二叉樹。
小頂堆:其中每個(gè)結(jié)點(diǎn)的關(guān)鍵字都不大于其孩子結(jié)點(diǎn)的關(guān)鍵字,這樣的堆稱為小頂堆(小根堆)。
大頂堆:其中每個(gè)結(jié)點(diǎn)的關(guān)鍵字都不小于其孩子結(jié)點(diǎn)的關(guān)鍵字,這樣的堆稱為大頂堆(大根堆)。
舉例來(lái)說(shuō)
對(duì)于n個(gè)元素的序列{R0, R1, … , Rn}當(dāng)且僅當(dāng)滿足下列關(guān)系之一時(shí),稱之為堆:
(1) Ri <= R2i+1 且 Ri <= R2i+2 (小頂堆)
(2) Ri >= R2i+1 且 Ri >= R2i+2 (大頂堆)
其中i=1,2,…,n/2向下取整
算法說(shuō)明
- 根據(jù)初始數(shù)組去構(gòu)造初始堆(構(gòu)建一個(gè)完全二叉樹,保證所有的父結(jié)點(diǎn)都比它的孩子結(jié)點(diǎn)數(shù)值大)。
- 每次交換第一個(gè)和最后一個(gè)元素,輸出最后一個(gè)元素(最大值),然后把剩下元素重新調(diào)整為大頂堆。
- 當(dāng)輸出完最后一個(gè)元素后,這個(gè)數(shù)組已經(jīng)是按照從小到大的順序排列了。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = HeapSort($list); print_r($res); function HeapSort($list) { $len = count($list); for ($i = floor(($len-2)/2); $i >= 0; $i--) { createHeap($list, $i, $len-1); } for ($i = $len-1; $i >=0 ; $i--) { swap($list, $i, 0); createHeap($list, 0, $i-1); } return $list; } function createHeap(&$list, $i, $j) { $target = $list[$i]; for ($m=$i*2+1; $m <= $j ; $m = $m*2+1) { if ($m < $j && $list[$m] < $list[$m+1]) { $m++; } if ($target > $list[$m]) { break; } $list[$i] = $list[$m]; $i = $m; } $list[$i] = $target; } function swap(&$list, $i, $j) { $temp = $list[$i]; $list[$i] = $list[$j]; $list[$j] = $temp; } |
歸并排序
算法說(shuō)明
歸并排序是將兩個(gè)或者兩個(gè)以上的有序表組合成一個(gè)新的有序表。
歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個(gè)非常典型的應(yīng)用。
將已有序的子序列合并,得到完全有序的序列;即先使每個(gè)子序列有序,再使子序列段間有序。若將兩個(gè)有序表合并成一個(gè)有序表,稱為二路歸并。
算法描述
- 將待排序序列R[0…n-1]看成是n個(gè)長(zhǎng)度為1的有序序列,將相鄰的有序表成對(duì)歸并,得到n/2個(gè)長(zhǎng)度為2的有序表;
- 將這些有序序列再次歸并,得到n/4個(gè)長(zhǎng)度為4的有序序列
- 如此反復(fù)進(jìn)行下去,最后得到一個(gè)長(zhǎng)度為n的有序序列。
歸并排序其實(shí)要做兩件事:
(1)“分解”——將序列每次折半劃分。
(2)“合并”——將劃分后的序列段兩兩合并后排序。
用例說(shuō)明
代碼實(shí)現(xiàn)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?php $list = array(49, 38, 65, 97, 76, 13, 27, 49); $res = MergeSort($list); print_r($res); function MergeSort(&$list) { $len = count($list); $res = array(); Msort($list, $res, 0, $len-1); return $res; } function MSort(&$list, &$res, $s, $t) { if ($s == $t) { $res[$s] = $list[$s]; }else{ $m = floor(($s + $t)/2); $temp = array(); //新建一個(gè)空數(shù)組 MSort($list, $temp, $s, $m); MSort($list, $temp, $m+1, $t); Merge($temp, $res, $s, $m, $t); } } function Merge(&$temp, &$res, $s, $m, $t) { for ($k = $s, $j = $m+1; $s <= $m && $j <= $t; $k++) { if ($temp[$s] < $temp[$j]) { $res[$k] = $temp[$s]; $s++; }else{ $res[$k] = $temp[$j]; $j++; } } if ($s <= $m) { for ($l = 0; $l <= $m-$s ; $l++) { $res[$k+$l] = $temp[$s+$l]; } } if ($j <= $t) { for ($l = 0; $l <= $t-$j ; $l++) { $res[$k+$l] = $temp[$j+$l]; } } } ?> |
基數(shù)排序
算法說(shuō)明
代碼實(shí)現(xiàn)
參考:
總結(jié)
以上是生活随笔為你收集整理的数据结构与算法(一)——排序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [转] Cisco路由器DNS配置
- 下一篇: kaggle使用笔记