九種經典排序演算法彙總
/*********************************************************** 總結各種排序演算法包括但不限於: 1. 插入排序類 1.1 直接插入排序 1.2 二分插入排序 1.3 希爾排序 2. 交換排序類 2.1 氣泡排序 2.2 快速排序 3. 選擇排序 3.1 直接選擇排序 3.2 堆排序 4. 歸併排序 5. 基數排序 以上所有排序演算法的實現均為將整形陣列data遞增排序 ************************************************************/ #include <iostream> #include <time.h> using namespace std; /********************** 1 直接插入排序******************************** 空間複雜度:只有輔助變數, 沒有與問題規模相關的輔存消耗,O(1) 時間複雜度:最好情況,初始陣列為正序(此處為遞增),O(n);最壞情況,初始陣列為反 序,O(n2);平均時間複雜度為O(n2). 穩定性:當data[i]=datda[i-1]時,相對位置不變,所以是穩定的排序 思想:將原序列分為有序區和無序區,每次外部迴圈將無序區的第一個元素插入到有序區的適 當位置,同時有序區元素加1,無序區元素減1,這樣直到無序區的元素為0 *******************************************************************/ void insertSort(int data[], int n) { int i, j; int tmp; for (i = 1; i < n; ++i) { tmp = data[i]; j = i - 1; while (j >= 0 && tmp < data[j]) { data[j + 1] = data[j]; --j; } //若j<0則tmp是有序區的最小元素,若tmp>=data[j]則將tmp放在data[j]的 //後面data[j+1]處 data[j + 1] = tmp; } } /************************ 2 二分(折半)插入排序 *********************** 時空複雜度及穩定性與上面是一樣的 思想:對於有序的序列二分查詢效率比順序查詢高很多,基於此,在將無序區的第一個元素插 入到有序區相應位置時,用二分查詢尋找該位置而不是順序查詢,可以減少關 鍵字比較的次數但是關鍵字移動的次數仍然是沒有改變的,所以其實際的效果與直接插 入排序相當,只需注意二分查詢思想的運用。 *******************************************************************/ void biInsertSort(int data[], int n) { int i, j, low, high, mid; int tmp; for (i = 1; i < n; ++i) { tmp = data[i]; low = 0, high = i - 1; while (low <= high) { mid = (low + high) / 2; if (tmp < data[mid]) high = mid - 1; else low = mid + 1; } for (j = i - 1; j >= high + 1; --j)//high+1 is mid data[j + 1] = data[j]; data[high + 1] = tmp; } } /************************* 3 希爾排序 ******************************** 空間複雜度:只用到了i,j,gap,tmp4個輔助變數,與問題規模無關,空間複雜度為O(1). 時間複雜度:分析較複雜,一般認為平均時間複雜度為O(n^1.3). 穩定性:不穩定 思想:本質上還是屬於插入排序,只不過是先對序列分組,然後組內直接插入,同時,分組數 由多到少,組內元素由少到多,順序性由差到好,直到最後一步組間距為1時, 直接插入排序的陣列已經基本有序了 *******************************************************************/ void shellSort(int data[], int n) { int i, j, gap; int tmp; gap = n / 2; while (gap > 0) { //這樣記憶,整個for迴圈其實就是直接插入排序的過程,只不過將直接插入排序 //的1->gap罷了,最後當gap=1的時候就是直接插入排序了。 for (i = gap; i < n; ++i) { tmp = data[i]; j = i - gap; while (j >= 0 && tmp < data[j]) { data[j + gap] = data[j]; j = j - gap; } data[j + gap] = tmp; } gap = gap / 2; } } /*************************** 4 氣泡排序 ****************************** 空間複雜度:只有三個輔助變數,與問題規模無關,空間複雜度為O(1) 時間複雜度:最好情況,陣列本身是正序的,O(n);最壞情況,陣列是反序的,O(n^2);平 均時間複雜度為O(n^2)。 穩定性:穩定 思想:將陣列頭部看成水面,陣列尾部看成水底,最小(或最大)的元素上浮(或下沉)直到 結束,採用的是比較元素大小然後交換元素值的思想,每次都選擇未排序的 元素中最小或最大元素送達指定的位置。 *******************************************************************/ //經典氣泡排序演算法,以後以這個為準 void bubbleSort(int data[], int n) { int i, j, tmp, flag; for (i = 0; i < n - 1; ++i) { flag = 0; for (j = 0; j < n - i - 1; ++j) { if (data[j] > data[j + 1]) { tmp = data[j]; data[j] = data[j + 1]; data[j + 1] = tmp; flag = 1; } } if (flag == 0) return; } } //最小元素上浮 void bubbleSort1(int data[], int n) { int tmp, flag; for (int i = 0; i < n - 1; ++i) { flag = 0; for (int j = n - 1; j > i; --j) { if (data[j] < data[j - 1]) { tmp = data[j]; data[j] = data[j - 1]; data[j - 1] = tmp; flag = 1; } } if (flag == 0)//no swap in the circulation return; } } //最大元素下沉(備選方案,與上面是一樣的) void bubbleSort2(int data[], int n) { int tmp, flag; for (int i = n-1; i > 0; --i) { flag = 0; for (int j = 0; j < i; ++j) { if (data[j] > data[j + 1]) { tmp = data[j]; data[j] = data[j + 1]; data[j + 1] = tmp; flag = 1; } } if (flag == 0) return; } } /***************************** 5 快速排序 **************************** 空間複雜度:主要是遞迴時所需的棧空間,平均空間複雜度為O(nlongn)。 時間複雜度:主要的時間都花費在劃分上面,最好情況,每次劃分的基準都是無序區的‘中 值’記錄,O(nlogn);最壞情況,原陣列本身是有序的,此時O(n^2)。 平均時間複雜度為O(nlogn)。 穩定性: 不穩定 思想:分治的思想,將大問題轉化為小問題,遞迴的思想,最重要的過程就是劃分,劃分結束 了,陣列也就排好序了,快速排序是排序演算法中非常重要的一種 *******************************************************************/ //快排,資料結構書上的方法,遞迴,以後以這個為準 void quickSort(int data[], int start, int end) { int i = start, j = end; int pivot; if (start < end) { //每次遞迴都取無序區的第一個元素作為中心基準,這個地方可以改進為隨機的方法 pivot = data[start]; while (i != j) { while (j>i && data[j] > pivot) --j; data[i] = data[j]; while (i < j && data[i] < pivot) ++i; data[j] = data[i]; } data[i] = pivot; quickSort(data, start, i - 1); quickSort(data, i + 1, end); } } //另外一個版本是將劃分(上面if裡面的程式碼)過程單獨成為一個partition函式,同時取樣隨機化快排思想(劍指offer) int randomInRange(int s, int t) { srand((unsigned int)time(NULL)); return s + rand() % (t - s + 1); } void swap(int* left, int* right) { int tmp = *left; *left = *right; *right = tmp; } int partition(int data[], int length, int start, int end) { if (data == NULL || start < 0 || end >= length) throw new std::exception("invalid parameters"); int index = randomInRange(start, end); swap(&data[index], &data[end]); int small = start - 1; for (index = start; index < end; ++index) { if (data[index] < data[end]) { ++small; if (small != index) swap(&data[index], &data[small]); } } ++small; swap(&data[small], &data[end]); return small; } void quickSort1(int data[], int length, int start, int end) { if (start == end) return; int index = partition(data, length, start, end); if (index > start) quickSort1(data, length, start, index - 1); if (index < end) quickSort1(data, length, index + 1, end); } /*************************** 6 直接選擇排序 ************************** 空間複雜度:只用到了i,j,k,tmp四個輔助變數,故空間複雜度為O(1). 時間複雜度:無論表的初始狀態如何,比較次數都達到O(n^2),故直接選擇排序的最好和最壞 時間複雜度都是O(n^2). 穩定性:不穩定,如將{5,3,2,5,4,1}排序,第一趟就改變了兩個5的相對位置。可以 看成是交換排序和直接插入排序的綜合,但是直接插入和氣泡排序都是穩定的,而該 演算法是不穩定的 思想:每一趟從待排序的記錄中選擇關鍵字最小的記錄,順序放在已排好序子表的最後,知道 全部記錄排序完畢 適用性:適合從大量記錄中選擇一部分排序記錄,如從10000個記錄中選擇關鍵字大小為前10 的記錄 *******************************************************************/ void selectSort(int data[], int n) { int tmp, k; for (int i = 0; i < n - 1; ++i) { k = i; for (int j = i + 1; j < n; ++j) { if (data[j] < data[k]) k = j; } if (k != i)//若k=i則證明已經是有序的了 { tmp = data[i]; data[i] = data[k]; data[k] = tmp; } } } /****************************** 7 堆排序 **************************** 空間複雜度:只用到了四個輔助變數,空間複雜度是O(1). 時間複雜度:最好,最壞,和平均時間複雜度都是O(nlogn). 穩定性:不穩定 思想:本質上是一種樹形選擇排序思想,將原陣列看成為一個完全二叉樹的順序儲存結構,利 用完全二叉樹中雙親節點和孩子節點之間的內在關係,在當前無序區中選擇關鍵字 最大(大根堆)或者最小(小根堆)的記錄移動到陣列的末尾,然後對剩餘的元素作同 樣的操作 適用性:不適宜記錄數較少的表,與直接選擇排序演算法類似 *******************************************************************/ //演算法分為兩個主要部分,堆調整(採用篩選演算法),與排序 //建立大根堆,每次將最大的元素移動到末尾 void heapAdjust(int data[], int start, int end) { int tmp = data[start]; for (int i = 2 * start + 1; i <= end; i *= 2){ //這個i<end的判斷很重要,若i=end,則證明當前節點start只有一個左孩子節點,就不用繼續比較了 if (i < end && data[i] < data[i + 1]) ++i; if (tmp > data[i]) break; data[start] = data[i]; start = i; } data[start] = tmp; } void heapAdjust1(int data[], int low, int high) { int i = low, j = 2 * i+1; int tmp = data[i]; while (j <= high) { if (j < high && data[j] < data[j + 1]) ++j; if (tmp < data[j]) { data[i] = data[j]; i = j; j = 2 * i; } else break; } data[i] = tmp; } void heapSort(int data[], int n) { int i; int tmp; //建立初始堆 for (i = n / 2; i >= 0; --i) { heapAdjust(data, i, n-1); } //堆排序過程 for (int i = n-1; i >= 0; --i) { //交換堆頂和最後一個元素 tmp = data[0]; data[0] = data[i]; data[i] = tmp; //調整堆滿足大根堆的性質 heapAdjust(data, 0, i - 1); } } /*************************** 8 歸併排序 ****************************** 空間複雜度:O(n),需要一個輔助的陣列來存放合併兩個有序表之後生成的新表,故歸併排序不是就地排序 時間複雜度:最好,最壞,平均時間複雜度均是O(nlogn) 穩定性:歸併排序是穩定的排序演算法 思想:將兩個或兩個以上的有序表合併為一個新的有序表,遞迴的思想 *******************************************************************/ ////迭代版本,有問題 //void mergeSort_iter(int data[], int n) //{ // int *b = new int[n]; // int *a = data; // //外層for迴圈,一共進行logn趟歸併 // for (int seg = 1; seg < n; seg += seg) // { // //一趟歸併排序 // for (int start = 0; start < n; start += seg + seg) // { // int low = start, mid = (start + seg) < n ? (start + seg) : n, high = (start + seg + seg) < n ? (start + seg + seg) : n; // int k = low; // int start1 = low, end1 = mid; // int start2 = mid, end2 = high; // while (start1 < end1 && start2 < end2) // b[k++] = a[start1] < a[start2] ? a[start1] : a[start2]; // while (start1 < end1) // b[k++] = a[start1++]; // while (start2 < end2) // b[k++] = a[start2++]; // } // //交換a和b // int *tmp = a; // a = b; // b = tmp; // } // //若發生交換了 // if (a != data) // { // for (int i = 0; i < n; ++i) // b[i] = a[i]; // b = a; // } // delete b; //} //一趟歸併過程,將兩個有序的子表合成一個新的有序表 void merge(int data[], int low, int mid, int high) { int i = low, j = mid + 1, k = 0; //臨時儲存排好序的陣列 int *tmp = new int[high - low + 1]; while (i <= mid && j <= high) { if (data[i] < data[j]) tmp[k++] = data[i++]; else tmp[k++] = data[j++]; } while (i <= mid) tmp[k++] = data[i++]; while (j <= high) tmp[k++] = data[j++]; for (int i = low, k = 0; i <= high; i++, k++) data[i] = tmp[k]; delete tmp; } //遞迴形式分別對陣列的左右兩個子陣列歸併排序,然後merge成一個新的有序陣列 void mergeSortR(int data[], int low, int high) { int mid; if (low < high) { mid = (low + high) / 2; mergeSortR(data, low, mid); mergeSortR(data, mid + 1, high); merge(data, low, mid, high); } } //自頂向下的二路歸併排序演算法 void mergeSort(int data[], int n) { mergeSortR(data, 0, n - 1); } /************************* 9 基數排序 ******************************** 空間複雜度:空間複雜度為O(n) 時間複雜度:最好、最壞、平均的時間複雜度都是O(d(n+r)),其中d是待排序元素的最大位 數,n是元素的個數,r是基數(十進位制r=10,二進位制r=2)。 穩定性:基數排序是穩定的排序方法 思想:通過"分配"和"收集"過程實現排序,不需要進行關鍵字之間的比較,是一種藉助於多 關鍵字排序的思想對單關鍵字排序的方法,分為最低位優先(LSD)和最高位優(MSD) *******************************************************************/ //輔助函式,求資料的最大位數d int maxbit(int data[], int n) { int d = 1;//儲存最大位數,初始為1 int p = 10; for (int i = 0; i < n; ++i) { while (data[i] >= p) { p *= 10;//有溢位的風險 ++d; } } return d; } //基數排序 void radixSort(int data[],int n) { //得到最大位數d int d = maxbit(data, n); int *tmp = new int[n]; int *count = new int[10];//計數器 int i, j, k; int radix = 1; for (i = 1; i <= d; ++i) { //清空計數器 for (j = 0; j < 10; ++j) count[j] = 0; for (j = 0; j < n; j++) { k = (data[j] / radix) % 10;//統計每個桶中的記錄數 count[k]++; } for (j = 1; j < 10; j++) count[j] = count[j - 1] + count[j]; for (j = n - 1; j >= 0; j--) { k = (data[j] / radix) % 10; tmp[count[k] - 1] = data[j]; count[k]--; } for (j = 0; j < n; j++) data[j] = tmp[j]; radix = radix * 10; } delete []tmp; delete []count; } void print(int data[], int n) { for (int i = 0; i < n; ++i) cout << data[i] << " "; cout << endl; } //測試 int main() { int data[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy1[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy2[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy3[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy4[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy5[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy6[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy7[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy8[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; int copy9[] = { 3, 6, 1, 5, 0, 4, 2, 9, 8, 7 }; cout << "待排序陣列為: "; print(data, sizeof(data) / sizeof(int)); cout << endl << endl; cout << "1 直接插入排序: "; insertSort(copy1, sizeof(copy1) / sizeof(int)); print(copy1, sizeof(copy1) / sizeof(int)); cout << endl; cout << "2 二分插入排序: "; biInsertSort(copy2, sizeof(copy2) / sizeof(int)); print(copy1, sizeof(copy2) / sizeof(int)); cout << endl; cout << "3 希爾排序: "; shellSort(copy3, sizeof(copy3) / sizeof(int)); print(copy1, sizeof(copy3) / sizeof(int)); cout << endl; cout << "4 氣泡排序: "; bubbleSort(copy4, sizeof(copy4) / sizeof(int)); print(copy1, sizeof(copy4) / sizeof(int)); cout << endl; cout << "5 快速排序: "; quickSort(copy5, 0, sizeof(copy5) / sizeof(int)-1); print(copy1, sizeof(copy5) / sizeof(int)); cout << endl; cout << "6 直接選擇排序: "; selectSort(copy6, sizeof(copy6) / sizeof(int)); print(copy1, sizeof(copy6) / sizeof(int)); cout << endl; cout << "7 堆排序: "; heapSort(copy7, sizeof(copy6) / sizeof(int)); print(copy1, sizeof(copy7) / sizeof(int)); cout << endl; cout << "8 歸併排序: "; mergeSort(copy8, sizeof(copy8) / sizeof(int)); print(copy1, sizeof(copy8) / sizeof(int)); cout << endl; cout << "9 基數排序: "; radixSort(copy9, sizeof(copy9) / sizeof(int)); print(copy1, sizeof(copy9) / sizeof(int)); cout << endl; return 0; }
相關推薦
九種經典排序演算法彙總
/*********************************************************** 總結各種排序演算法包括但不限於: 1. 插入排序類 1.1 直接插入排序 1.2 二分插入排序 1.3 希爾排序 2. 交換排序類 2.1 氣泡排序
九種經典排序演算法詳解(氣泡排序,插入排序,選擇排序,快速排序,歸併排序,堆排序,計數排序,桶排序,基數排序)
綜述 最近複習了各種排序演算法,記錄了一下學習總結和心得,希望對大家能有所幫助。本文介紹了氣泡排序、插入排序、選擇排序、快速排序、歸併排序、堆排序、計數排序、桶排序、基數排序9種經典的排序演算法。針對每種排序演算法分析了演算法的主要思路,每個演算法都附上了虛擬
八種經典排序演算法和java實現
文章目錄 演算法概述 演算法分類 演算法複雜度 相關概念 1.氣泡排序(Bubble Sort)
常見14種經典排序演算法(Java程式碼實現)
尊重原創,轉載請標明出處 http://blog.csdn.net/abcdef314159 ,想了解更多演算法題可以關注微信公眾號“資料結構和演算法”,每天一題為你精彩解答。 一,氣泡排序 排序演算法其實有很多,氣泡排序基本上算是最簡單的一種
7種經典排序演算法Java程式碼實現(冒泡+選擇+插入+歸併+快排+堆排序+希爾)
氣泡排序 氣泡排序的原理是:比較兩個相鄰的元素,將值較大的元素交換到至右端(比較+移動) public static void sortMpao(int[] num) { for(int i = 1; i < num.length; i++) {
剖析八種經典排序演算法
排序(Sorting) 是計算機程式設計中的一種重要操作,它的功能是將一個數據元素(或記錄)的任意序列,重新排列成一個關鍵字有序的序列。 我整理了以前自己所寫的一些排序演算法結合網上的一些資料,共介紹8種常用的排序演算法,希望對大家能有所幫助。 八種排序
幾種經典排序演算法的JS實現方法+隨機洗牌演算法
一.氣泡排序functionBubbleSort(array) { var length = array.length; for(var i = length - 1; i > 0; i--) { //用於縮小範圍 for(var j = 0; j
九種基本排序演算法總結
排序分類: 1、插入排序:直接插入排序,二分法插入排序,希爾排序; 2、選擇排序:簡單選擇排序,堆排序; 3、交換排序:氣泡排序,快速排序; 4、歸併排序; 5、基數排序; (1)直接插入排序:(穩定排序) 基本思想:將每個待排序的記錄,按照其順序碼的大小插入到前
基於python的七種經典排序演算法
參考書目:《大話資料結構》 一、排序的基本概念和分類 所謂排序,就是使一串記錄,按照其中的某個或某些關鍵字的大小,遞增或遞減的排列起來的操作。排序演算法,就是如何使得記錄按照要求排列的方法。 排序的穩定性: 經過某種排序後,如果兩個記錄序號
各種經典排序演算法彙總( 親測除錯運算通過)
這幾天好好學習了一下排序演算法 查看了各種書籍和網路資源 挑著簡單易懂的教程好好學習了一下 基本上算是過了一遍 之後幾天 對排序演算法好好地總結一下 整理一下,先把要整理的演算法列舉一下: 1,選擇排序 對於一個a[0,n]的陣列,依次遍歷陣列,每次選出最大或最小的一個
1T資料快速排序!十種經典排序演算法總結
# 1 氣泡排序 每次迴圈都比較前後兩個元素的大小,如果前者大於後者,則將兩者進行交換。這樣做會將每次迴圈中最大的元素替換到末尾,逐漸形成有序集合。將每次迴圈中的最大元素逐漸由隊首**轉移**到隊尾的過程形似“冒泡”過程,故因此得名。 一個優化氣泡排序的方法就是如果在一次迴圈的過程中沒有發生交換,則可以立
7種排序演算法彙總
排序演算法 1. 氣泡排序 平均時間複雜度O(n2)O(n2) ( 最好O(n)O(n),最差O(n2)O(n2) ) 空間複雜度O(1)O(1) 穩定排序 程式碼如下 void BubbleSort(vector&
五種C語言非數值計算的常用經典排序演算法
摘要:排序是計算機的一種操作方法,其目的是將一組“無序”的記錄序列調整為“有序”的記錄序列,主要分為內部排序和外部排序。 排序 排序是計算機的一種操作方法,其目的是將一組“無序”的記錄序列調整為“有序”的記錄序列,主要分為內部排序和外部排序。 (1)氣泡排序(起泡排序) 氣泡排序(Bubble Sort),其
十大經典排序演算法(動圖演示) 十大經典排序演算法(動圖演示)
十大經典排序演算法(動圖演示) 0、演算法概述 0.1 演算法分類 十種常見排序演算法可以分為兩大類: 非線性時間比較類排序:通過比較來決定元素間的相對次序,由於其時間複雜度不能突破O(nlogn),因此稱為非線性時間比較類排序。 線性
經典排序演算法(Java版)
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
Java-經典排序演算法(二)——快速排序
快速排序 快速排序之所以比較快,是因為相比氣泡排序,每次交換是跳躍式的。每次排序的時候設定一個基準點,將小於等於基準點的數全部放到基準點的左邊,將大於等於基準點的數全部放到基準點的右邊。這樣在每次交換的時候就不會像氣泡排序一樣只能在相鄰的數之間進行交換,交換的距離就大得多了。因此總的比較和交
Java-經典排序演算法(一)
前言: 排序演算法有很多種,如選擇排序、插入排序、氣泡排序、桶排序、快速排序等等。這裡介紹的是簡化版桶排序、氣泡排序和插入排序。 推薦一本演算法入門書——《啊哈!演算法》 1. 桶排序[簡化版]: 原理:新建一個book陣列用來標記原陣列每一個數字出現的個數。
經典排序演算法 - 氣泡排序Bubble Sort
最近學習了一下排序演算法,寫篇文章記錄一下,詳細講解網上有很多,可以自己去查 氣泡排序Bubble Sort 氣泡排序是通過兩兩比較,最大的往後移,重複這一過程直到資料不再交換,則排序完成。氣泡排序的時間複雜度是O(n²),是穩定排序。 演算法描述(Java):
經典排序演算法 - 插入排序Insert Sort
最近學習了一下排序演算法,寫篇文章記錄一下,詳細講解網上有很多,可以自己去查 插入排序Insert Sort 直接插入排序就是依次將無序表中的資料插入到有序表的適當位置,使有序表仍有序,直到全部插入為止。插入排序的時間複雜度是O(n²),是穩定排序。 [ 2
經典排序演算法之--選擇排序
瞭解了前兩種排序演算法,再來看選擇排序已經很簡單了,它的思路是: 從一堆序列中,選擇一個最小的數,作為新的有序序列的頭,剩下的元素依次重複這一過程。 核心程式碼如下: for(int i=0;i<a.length;i++