部分摘選自
本部落格限於本人自學,更加內容請參閱↑鏈結
十種常見排序演算法可以分為兩大類:
比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破o(nlogn),因此也稱為非線性時間比較類排序。
非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基於比較排序的時間下界,以線性時間執行,因此也稱為線性時間非比較類排序。(本文暫不涉及)
直接插入排序(straight insertion sort)是一種最簡單的排序方法,其基本操作是將一條記錄插入到已排好的有序表中,從而得到乙個新的、記錄數量增1的有序表。
一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:
從第乙個元素開始,該元素可以認為已經被排序;
取出下乙個元素,在已經排序的元素序列中從後向前掃瞄;
如果該元素(已排序)大於新元素,將該元素移到下一位置;
重複步驟3,直到找到已排序的元素小於或者等於新元素的位置;
將新元素插入到該位置後;
重複步驟2~5。
void
sort1
(int a,
int n)
a[j+1]
= a[0]
;//a[j]比a[0]小或等於}}
}
折半插入排序演算法是一種穩定的排序演算法,比直接插入演算法明顯減少了關鍵字之間比較的次數,因此速度比直接插入排序演算法快,但記錄移動的次數沒有變,所以折半插入排序演算法的時間複雜度仍然為o(n^2),與直接插入排序演算法相同。附加空間o(1)。
折半查詢只是減少了比較次數,但是元素的移動次數不變,所以時間複雜度為o(n^2)是正確的!
void
sort0
(int a,
int n)
else
high = mid -1;
}for
(j = i -
1; j >= high +
1; j--
) a[high +1]
= a[0];}}
先將整個待排序的記錄序列分割成為若干子串行分別進行直接插入排序,具體演算法描述:
選擇乙個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列個數k,對序列進行k 趟排序;
每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子串行,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為乙個表來處理,表長度即為整個序列的長度。
//本**是從a[0]開始排序的,其他從a[1]開始,a[0]是哨兵;這個以後改進吧,睡啦
void
sort2
(int a,
int n)
a[gap + k]
= temp;}}}}}
穩定排序演算法
比較相鄰的元素。如果第乙個比第二個大,就交換它們兩個;
對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數;
針對所有的元素重複以上的步驟,除了最後乙個;
重複步驟1~3,直到排序完成。
void
sort3
(int
* a,
int n)}}
}
時間複雜度o(nlog2n) 空間複雜度o(log2n)
從數列中挑出乙個元素,稱為 「基準」(pivot);
重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;
遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
//一趟劃分
intpartition
(int
* a,
int low,
int high)
a[i]
= a[0]
;return i;
}//快速排序
void
sort4
(int
* a,
int low,
int high)
}
在簡單選擇排序過程中,所需移動記錄的次數比較少。最好情況下,即待排序記錄初始狀態就已經是正序排列了,則不需要移動記錄。
最壞情況下,即待排序記錄初始狀態是按第一條記錄最小,之後的記錄從小到大順序排列,則需要移動記錄的次數最多為3(n-1)。簡單選擇排序過程中需要進行的比較次數與初始狀態下待排序的記錄序列的排列情況無關。當i=1時,需進行n-1次比較;當i=2時,需進行n-2次比較;依次類推,共需要進行的比較次數是(n-1)+(n-2)+…+2+1=n(n-1)/2,即進行比較操作的時間複雜度為o(n^2),進行移動操作的時間複雜度為o(n)。
簡單選擇排序是不穩定排序。
(1)從待排序序列中,找到關鍵字最小的元素;
(2)如果最小元素不是待排序序列的第乙個元素,將其和第乙個元素互換;
(3)從餘下的 n - 1 個元素中,找出關鍵字最小的元素,重複(1)、(2)步,直到排序結束。
void
sort5
(int
* a,
int n)
if(j != i)
}}
參考鏈結
將初始待排序關鍵字序列(r1,r2….rn)構建成大頂堆,此堆為初始的無序區;
將堆頂元素r[1]與最後乙個元素r[n]交換,此時得到新的無序區(r1,r2,……rn-1)和新的有序區(rn),且滿足r[1,2…n-1]<=r[n];
由於交換後新的堆頂r[1]可能違反堆的性質,因此需要對當前無序區(r1,r2,……rn-1)調整為新堆,然後再次將r[1]與無序區最後乙個元素交換,得到新的無序區(r1,r2….rn-2)和新的有序區(rn-1,rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。
//建堆
void
heapadjust
(int
* a,
int s,
int m)
//應插入的位置在 s 處
a[s]
= a[0]
;}//堆排序
void
sort6
(int
* a,
int n)
for(i = n; i >1;
--i)
}
把長度為n的輸入序列分成兩個長度為n/2的子串行;
對這兩個子串行分別採用歸併排序;
將兩個排序好的子串行合併成乙個最終的排序序列。
//兩路歸併
void
merge
(int
* a,
int i,
int m,
int n)
for(
; i <= m;
) temp[k++
]= a[i++];
for(
; j <= n;
) temp[k++
]= a[j++];
for(i = b, k =
1; i <= n;
) a[i++
]= temp[k++];
}//歸併排序
void
sort7
(int
* a,
int s,
int t)
}
西電複試之 真題2008E
精度計算問題 輸入 每組資料佔一行,用一對資料表示,第乙個資料是r 含小數點共六位 第二個資料是階數n 輸出 輸出計算結果 include include include using namespace std 函式用於計算x的n次方,存入a陣列 voidf int a,int x,int n in...
C 西電複試2011PronlemD
通訊電文n個字元 4,30 每個字元出現的頻度wi 根據權值構建哈夫曼樹,計算帶權路徑長度 cin n個 頻度wi cout 帶權路徑長度 queue int name name.front 隊首 name.back 隊尾 name.push temp 入隊 name.pop 出隊 name.emp...
程式設計學習 演算法之排序小結
首先,國際慣例 一 什麼是排序演算法?所謂排序,就是使一串記錄,按照其中的某個或某些關鍵字的大小,遞增或遞減的排列起來的操作。排序演算法,就是如何使得記錄按照要求排列的方法。排序演算法在很多領域得到相當地重視,尤其是在大量資料的處理方面。乙個優秀的演算法可以節省大量的資源。在各個領域中考慮到資料的各...