數據結構排序算法的概念是從網上抄錄的:
基本概念:
1、 排序:按照一定的關鍵字,將一個序列排列成想要得到的一個新的序列。
2、 內部排序和外部排序:整個排序過程完全在內存中進行,叫做內部排序。數據量較大需要藉助外部存儲設備才能完成,叫做外部排序。
3、 主關鍵字和此關鍵字:
4、 排序的穩定性:對於相同的元素來說,在排序之前和之後的書訊是一樣的,那麼這種排序就是穩定的排序,如果順序發生了變化,那麼就是不穩定排序。
插入類排序:
(一) 思想:在一個已經排好序的序列中,將未被排進的元素按照原先的規定插入到指定位置。
(二) 分類:
1、 直接插入排序:
① 思想:最基本的插入排序,將第i個插入到前i-1箇中的適當位置。
② 時間複雜度:T(n) = O(n)。
③ 空間複雜度:S(n) = O(1)。
④ 穩定性:穩定排序。循環條件while(r[0].key < r[j].key)保證的。
⑤ 程序:
/** * 直接插入排序: * 1.從第一個元素開始,該元素可以認爲已經被排序 * 2.取出下一個元素,在已經排序的元素序列中從後向前掃描 * 3.如果該元素小於前面的元素(已排序),則依次與前面元素進行比較如果小於則交換,直到找到大於該元素的就則停止; * 4.如果該元素大於前面的元素(已排序),則重複步驟2 5.重複步驟2~4 直到所有元素都排好序 。 * * @param a */ public static void insert(int[] a) { for (int i = 1; i < a.length; i++) { int key = a[i]; for (int j = i - 1; j >= 0; j--) { if (key < a[j]) { int temp = a[j]; a[j] = key; a[i] = temp; i = j; } } } }
2、 折半插入排序:
① 思想:因爲是已經確定了前部分是有序序列,所以在查找插入位置的時候可以用折半查找的方法進行查找,提高效率。
② 時間複雜度:比較時的時間減爲O(n㏒n),但是移動元素的時間耗費未變,所以總是得時間複雜度還是O(n)。
③ 空間複雜度:S(n) = O(1)。
④ 穩定性:穩定排序。
⑤ 程序:
/** * 折半插入排序: * 在將一個新元素插入已排好序的數組的過程中,尋找插入點時, 將待插入區域的首元素設置爲a[low],末元素設置爲a[high], * 比較時將待插入元素與a[m],其中m=(low+high)/2相比較,如果比參考元素大, * 則選擇a[low]到a[m-1]爲新的插入區域(即high=m-1), 否則選擇a[m+1]到a[high]爲新的插入區域(即low=m+1), * 如此直至low<=high不成立,即將此位置之後所有元素後移一位, 並將新元素插入a[high+1]。 * * @param a */ public static void binaryInsert(int[] a) { // {1, 5, 5, 3, 4, 3,2} for (int i = 1; i < a.length; i++) { int key = a[i]; int low = 0; int high = i - 1; while (low <= high) { int mid = (low + high) / 2; if (key < a[mid]) { high = mid - 1; } else { low = mid + 1; } } System.out.println("low:" + low + ",high:" + high + ",i:" + i + ",key:" + key); for (int j = i; j > high + 1; j--) { a[j] = a[j - 1]; } a[high + 1] = key; } }
3、shell排序
交換類排序:
(一) 思想:通過交換逆序元素進行排序的方法。
(二) 分類:
1、 冒泡排序:
① 思想:反覆掃描待排序序列,在掃描的過程中順次比較相鄰的兩個元素的大小,若逆序就交換位置。第一趟,從第一個數據開始,比較相鄰的兩個數據,(以升序爲例)如果大就交換,得到一個最大數據在末尾;然後進行第二趟,只掃描前n-1個元素,得到次大的放在倒數第二位。以此類推,最後得到升序序列。如果在掃描過程中,發現沒有交換,說明已經排好序列,直接終止掃描。所以最多進行n-1趟掃描。
② 時間複雜度:T(n) = O(n)。
③ 空間複雜度:S(n) = O(1)。
④ 穩定性:穩定排序。
⑤ 程序:
/** * 冒泡排序: * 依次比較相鄰的兩個數,將小數放在前面,大數放在後面。 即在第一趟:首先比較第1個和第2個數,將小數放前,大數放後。 * 然後比較第2個數和第3個數,將小數放前,大數放後,如此繼續, 直至比較最後兩個數,將小數放前,大數放後。 至此第一趟結束,將最大的數放到了最後。 * 依次執行以上步驟a.leng-1次,排序完成。 * * @param a */ public static void bubble(int[] a) { // {1, 5, 5, 3, 4, 3,2} for (int i = 1; i < a.length; i++) { for (int j = 0; j < a.length - i; j++) { if (a[j + 1] < a[j]) { int temp = a[j + 1]; a[j + 1] = a[j]; a[j] = temp; } } } }
2、 快速排序:
① 思想:冒泡排序一次只能消除一個逆序,爲了能一次消除多個逆序,採用快速排序。以一個關鍵字爲軸,從左從右依次與其進行對比,然後交換,第一趟結束後,可以把序列分爲兩個子序列,然後再分段進行快速排序,達到高效。
② 時間複雜度:平均T(n) = O(n㏒n),最壞O(n)。
③ 空間複雜度:S(n) = O(㏒n)。
④ 穩定性:不穩定排序。{3, 2, 2}
⑤ 程序:
/** * 快速排序: * 一趟快速排序的算法是: * 1)設置兩個變量l、h,排序開始的時候:l=0,h=N-1; * 2)以第一個數組元素作爲關鍵數據,賦值給key,即key=A[0]; * 3)從j開始向前搜索,即由後開始向前搜索,找到第一個小於key的值A[j],將A[j]和A[i]互換,然後h--; * 4)從i開始向後搜索,即由前開始向後搜索,找到第一個大於key的A[i],將A[i]和A[j]互換,然後l++; * 5)重複第3、4步,直到l==h * * @param a */ public static void quick(int[] a, int l, int h) { int low = l; int high = h; int key = a[low]; while (low < high) { //從後往前找 while (low < high && key < a[high]) { high--; } if (low < high) { int temp = a[high]; a[high] = a[low]; a[low] = temp; low++; } //從前往後找 while (low < high && key > a[low]) { low++; } if (low < high) { int temp = a[high]; a[high] = a[low]; a[low] = temp; high--; } } if (low > l) { quick(a, l, low-1); } if (high < h) { quick(a, high+1, h); } }
選擇類排序:
(一) 思想:每一趟在n – i + 1 ( i = 1,2, … , n - 1)個記錄中選取關鍵字最小的記錄作爲有序序列中的第i個記錄。
(二) 分類:
1、 簡單選擇排序:
① 思想:第一趟時,從第一個記錄開始,通過n – 1次關鍵字的比較,從n個記錄中選出關鍵字最小的記錄,並和第一個記錄進行交換。第二趟從第二個記錄開始,選擇最小的和第二個記錄交換。以此類推,直至全部排序完畢。
② 時間複雜度:T(n) = O(n)。
③ 空間複雜度:S(n) = O(1)。
④ 穩定性:不穩定排序,{3, 3, 2}。
⑤ 程序:
/** * 選擇排序: * 在第一趟遍歷N個數據,找出其中最小的數值與第一個元素交換, * 第二趟遍歷剩下的N-1個數據,找出其中最小的數值與第二個元素交換...... * 第N-1趟遍歷剩下的2個數據,找出其中最小的數值與第N-1個元素交換, * 至此選擇排序完成。 * @param a */ public static void selectSort(int[] a) { //{ 1, 5, 5, 3, 4, 3, 2 }; for(int i=1; i<a.length; i++) { int flag = i-1; for(int j=i; j<a.length; j++) { if(a[flag] > a[j]) { flag = j; } } if(flag != i-1) { int temp = a[flag]; a[flag] = a[i-1]; a[i-1] = temp; } toString(a); } }
3、 堆排序:
① 思想:把待排序記錄的關鍵字存放在數組r[1…n]中,將r看成是一刻完全二叉樹的順序表示,每個節點表示一個記錄,第一個記錄r[1]作爲二叉樹的根,一下個記錄r[2…n]依次逐層從左到右順序排列,任意節點r[i]的左孩子是r[2i],右孩子是r[2i+1],雙親是r[i/2向下取整]。然後對這棵完全二叉樹進行調整建堆。
② 時間複雜度:T(n) = O(n㏒n)。
③ 空間複雜度:S(n) = O(1)。
④ 穩定性:不穩定排序。{5, 5, 3}