待續算法
(原創,轉發須註明原處)編程
算法是個很奇妙的東西,無論在招聘的筆試仍是面試中,也無論你是學的什麼語言或者什麼方向的編程,出題者或面試官總會問問,尤爲是關於排序算法的問題,對滴,在此次秋招中,我就被面試官問了無數次(有點誇張)。下面,我就好好總結總結下,我相信,之後絕對有人用得上的,方便點。。。數組
1、關於排序的概念大數據
對的,就是概念,要學好一個東西,必需要先搞清概念,別一上來就看題敲代碼,這是初學者浮躁的表現(我當初就是這樣的),總想急於求成,想快點作點東西,當時確實學到了很多零碎的知識,但隨着內容的深刻與擴充,發現本身學的東西變得多而雜了,因而,又花更多的時間去理清知識體系。因此,我勸你們應該有個好的起點,從開始就弄清本身到底要學啥,學了些啥,有個清晰的知識體系會有助於我更好的深刻。廢話就很少說了。。。
spa
排序法指針 |
最差時間分析 | 平均時間複雜度 | 穩定度 | 空間複雜度 |
冒泡排序 | O(n2) | O(n2) | 穩定 | O(1) |
快速排序 | O(n2) | O(n*log2n) | 不穩定 | O(log2n)~O(n) |
選擇排序 | O(n2) | O(n2) | 穩定 | O(1) |
二叉樹排序 | O(n2) | O(n*log2n) | 不一頂 | O(n) |
插入排序code |
O(n2) | O(n2) | 穩定 | O(1) |
堆排序 | O(n*log2n) | O(n*log2n) | 不穩定 | O(1) |
希爾排序 | O | O | 不穩定 | O(1) |
2、算法講解與實現部分htm
一、簡單選擇排序
大體過程:首先,選出數組中最小的元素,將它與數組中第一個元素進行交換,而後找出次小的元素,並將它與數組中第二個元素進行交換。按照這種方法一直進行下去,知道整個數組排序完爲止。圖解以下:
代碼以下:
void selectsort(int a[],int length) { int i, j; for (i = 0; i < length; i++) { int min = i; for (j = i + 1; j < length; j++) if (a[j] < a[min]) min = j; if (min != i) { int t = a[i]; a[i] = a[min]; a[min] = t; } } }
缺點:比較次數多,不能利用數據的已有序的特色,對已有序的部分依賴弱
優勢:屬於穩定排序,對於元素較大,但關鍵字又比較小的數據的排序,選擇排序較適合
二、插入排序
大體思路:每次將一個待排序的元素與已排序的元素進行逐一比較,直到找到合適的位置按大小插入。
代碼以下:
void insertion(int a[], int length) { int i, j; for (i = 1; i < length; i++) for (j = i; j > 0; j--) if (a[j - 1] > a[j]) { int t = a[j - 1]; a[j - 1] = a[j]; a[j] = t; } }
改進下:
void insertion(int a[], int length) { for (int i = 1; i < length; i++)//從第2個數據開始插入 { int j = i - 1; int t = a[i];//記錄要插入的數據 while (j >= 0 && a[j] > t)//從後向前,找到比其小的數的位置 a[j + 1] = a[j--];//向後挪動 if (j != i - 1)//存在比其小的數 a[j + 1] = t; } }
優勢:穩定,而且對數據的初始排列順序很敏感,若是數據量很大時,且關鍵字已經部分排序,則插入排序速度比較快
缺點:對於順序結構的數據,比較次數不必定,比較次數越少,插入點後的數據移動越多,特別是當數據總量龐大的時候。
三、冒泡排序
大體思路:遍歷待排序的數據,若是鄰近的兩個元素大小順序不對,就將兩者進行交換操做,重複此操做直到全部數據排序好爲止。圖解以下:
代碼以下:
void bubble(int a[], int length) { for(int i=0;i<length-1;i++)//進行(n-1)次 for(int j=length-1;j>i;j--) if(a[j-1]>a[j]) { int t = a[j]; a[j] = a[j - 1]; a[j - 1] = t; } }
改進:
void bubble(int a[], int length) { //若是a[0..i]已經是有序區間,上次的掃描區間是a[i..length], //記上次掃描時最後一次執行交換的位置爲pos, //則pos在i與length之間,則a[i..pos]區間也是有序的, //不然這個區間也會發生交換;因此下次掃描區間就能夠由a[i..length] //縮減到[pos..n] int pos = 0, tpos = 0; for (int i = 0; i < length - 1; i++) { pos = tpos; for (int j = length - 1; j > pos; j--) { if (a[j - 1] > a[j]) { int t = a[j]; a[j] = a[j - 1]; a[j - 1] = t; tpos = j; } } //若是通過一次掃描後位置沒變則表示已經所有有序 if (pos == tpos) break; } }
附上雙向冒泡(抖動冒泡):
void ImpButtle(int a[], int length) { //先讓冒泡排序由左向右進行,再來讓冒泡排序由右往左進行"抖動"排序 int left = 0, right = length - 1, i, flag=0; while (left < right) { for(i=left;i<right;i++) if (a[i] > a[i + 1]) { int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t; flag = i; } right = flag; for(i=right;i>left;i--) if (a[i - 1] > a[i]) { int t = a[i - 1]; a[i - 1] = a[i]; a[i] = t; flag = i; } left = flag; } }
(注:插入排序不能預知各個數據在數組中的最終位置,選擇排序不會改變已排序好的數據的位置。插入排序每步中要平均移動已排序好的數據的通常長度,選擇排序和冒泡排序每步都要訪問全部還沒有排序的數據,其中,冒泡排序將全部順序不對的相鄰的元素進行交換,而選擇排序每步中只交換一次。
選擇排序:N^2/2次比較操做 N次交換操做;插入排序:平均狀況下,大約N^2/4次比較操做 N^2/4次交換操做,在最壞狀況下都須要2倍的數量;冒泡排序:在平均和最壞狀況下,執行大約N^2/2次比較操做和N^2/2次交換操做
對於數據項較大,關鍵字較小的數據,選擇排序的運行時間是線性的)
四、希爾排序(縮小增量排序)
大體思路:是直接插入排序算法的一種更高效的改進版本。它容許非相鄰的元素進行交換來提升執行效率。先取一個小於n的整數d1做爲第一個增量,把文件的所有記錄分組。全部距離爲d1的倍數的記錄放在同一個組中。先在各組內進行直接插入排序;而後,取第二個增量d2<d1重複上述的分組和排序,直至所取的增量 =1( < …<d2<d1),即全部記錄放在同一組中進行直接插入排序爲止。圖解以下:
代碼以下:
void Shellsort(int a[], int length) { for(int gap=length/2;gap>0;gap/=2)//此處步長每次減半
for(int i=gap;i<length;i++)//各組中分別進行插入排序 for (int j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) { int t = a[j]; a[j] = a[j + gap]; a[j + gap] =t; } }
優勢:快,數據移動少; 缺點:不穩定,d的取值是多少,應取多少個不一樣的值,都沒法確切知道,只能憑經驗來取(即不一樣的步長致使算法效率不一樣)。