日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结

發布時間:2024/7/5 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、快速排序的基本思想
???  設當前待排序的無序區為R[low..high],利用分治法可將快速排序的基本思想描述為:
①分解:
???  在R[low..high]中任選一個記錄作為基準(Pivot),以此基準將當前無序區劃分為左、右兩個較小的子區間R[low..pivotpos-1)和R[pivotpos+1..high],并使左邊子區間中所有記錄的關鍵字均小于等于基準記錄(不妨記為pivot)的關鍵字pivot.key,右邊的子區間中所有記錄的關鍵字均大于等于pivot.key,而基準記錄pivot則位于正確的位置(pivotpos)上,它無須參加后續的排序。
? 注意:
???  劃分的關鍵是要求出基準記錄所在的位置pivotpos。劃分的結果可以簡單地表示為(注意pivot=R[pivotpos]):
???  R[low..pivotpos-1].keys≤R[pivotpos].key≤R[pivotpos+1..high].keys
????????????????? 其中low≤pivotpos≤high。
②求解:
??   通過遞歸調用快速排序對左、右子區間R[low..pivotpos-1]和R[pivotpos+1..high]快速排序。

完整的代碼如下:

#include<iostream> #include<stack> using namespace std; int partition(int *arr , int low , int high) {int pivo = arr[low];while(low < high){while(low < high && arr[high] >= pivo)--high;arr[low] = arr[high];while(low < high && arr[low] <= pivo)++low;arr[high] = arr[low];}arr[low] = pivo;return low; }// 快速排序 遞歸 void qsort(int *arr , int low , int high) {if(low < high){int pivo = partition(arr , low , high);qsort(arr , low , pivo-1);qsort(arr , pivo+1 , high);} }// 快速排序 非遞歸 void qsort_no_recursive(int *arr , int low , int high) {stack<int>s;int pivo;if(low < high){pivo = partition(arr , low , high);if(low < pivo - 1){s.push(low);s.push(pivo-1);}if(pivo + 1 < high){s.push(pivo+1);s.push(high);}while(!s.empty()){high = s.top();s.pop();low = s.top();s.pop();pivo = partition(arr , low , high);if(low < pivo - 1){s.push(low);s.push(pivo-1);}if(pivo + 1 < high){s.push(pivo+1);s.push(high);}}//while}//if }//簡單示例 ? int main(void) ? { ?int i , a[11] = {20,11,12,5,6,13,8,9,14,7,10}; ?printf("排序前的數據為:\n"); ?for(i = 0 ; i < 11 ; ++i) ?printf("%d ",a[i]); ?printf("\n"); ?//qsort(a , 0 , 10);qsort_no_recursive(a , 0 , 10);printf("排序后的數據為:\n"); ?for(i = 0 ; i < 11 ; ++i) printf("%d ",a[i]); ?printf("\n");return 0; ? } 二、希爾排序
???? 希爾排序(Shell Sort)又稱為縮小增量排序,輸入插入排序算法,是對直接排序算法的一種改進。本文介紹希爾排序算法。
???? 對于插入排序算法來說,如果原來的數據就是有序的,那么數據就不需要移動,而插入排序算法的效率主要消耗在數據的移動中。因此可知:如果數據的本身就是有序的或者本身基本有序,那么效率就會得到提高。
???? 希爾排序的基本思想是:將需要排序的序列劃分成為若干個較小的子序列,對子序列進行插入排序,通過則插入排序能夠使得原來序列成為基本有序。這樣通過對較小的序列進行插入排序,然后對基本有序的數列進行插入排序,能夠提高插入排序算法的效率。
???? 在希爾排序中首先解決的是子序列的選擇問題。對于子序列的構成不是簡單的分段,而是采取相隔某個增量的數據組成一個序列。
增量一般的選擇原則是:取上一個增量的一半作為此次序列的劃分增量。首次選擇序列長度的一為增量。
???? 先假如:數組的長度為10,數組元素為:25、19、6、58、34、10、7、98、160、0
???? 整個希爾排序的算法過程如下如所示:


上圖是原始數據和第一次選擇的增量 d = 5。本次排序的結果如下圖:

上圖是第一次排序的結果,本次選擇增量為 d=2。 本次排序的結果如下圖:

當d=1 是進行最后一次排序,本次排序相當于冒泡排序的某一次循環。最終結果如下:

在實際使用過程中,帶排序的數據肯定不是只有十個,但是上述是希爾排序的思想。其實希爾排序只是插入排序的一種優化。
C++實現希爾排序的代碼如下所示:
#include<iostream> using namespace std;void shell_sort(int array[] , int length) {int i , j , temp;int d = length/2;?????? // 設置希爾排序的初始增量while(d >= 1){for(i = d ; i < length ; ++i){temp = array[i];j = i - d;?????? // 步長為d的前面一個位置while(j >= 0 && array[j] > temp)??????? // 從后往前進行插入排序{array[j + d] = array[j];j -= d;}array[j + d] = temp;???? // 找到了插入位置}d /= 2;} }int main(void) {int i , a[]={25,19,6,58,34,10,7,98,160,0};shell_sort(a , 10);for(i = 0 ; i < 10 ; ++i)cout<<a[i]<<" ";cout<<endl;system("pause");return 0; }// 模板 template<class T> void ShellSort(T *a,int len) //希爾排序算法 {int gap , j;for(gap = len / 2 ; gap > 0 ; gap /= 2){for(j = gap;j < len ; ++j) //j從gap個元素開始{if(a[j] < a[j - gap]) //每個元素與自己組內的數據進行直接插入排序{T temp = a[j];int k = j - gap;while(k >= 0 && a[k] > temp){a[k + gap] = a[k];k -= gap;}a[k + gap] = temp;}}} } 三、插入排序
直接插入排序(direct Insert Sort)的基本思想是:順序地將待排序的記錄按其關鍵碼的大小插入到已排序的記錄子序列的適當位置。子序列的記錄個數從1開始逐漸增大,當子序列的記錄個數與順序表中的記錄個數相同時排序完畢。
void InsertSort(int array[] , int length) // 無哨兵的插入排序 {int i , j , temp;for(i = 1 ; i < length ; ++i){if(array[i] < array[i-1]){temp = array[i];for(j = i - 1 ; j >= 0 && array[j] > temp ;--j)array[j + 1] = array[j];array[j + 1] = temp;}} }void InsertSort(int array[] , int length) // 有哨兵的插入排序 {int i , j ;for(i = 1 ; i <= length ; ++i){if(array[i] < array[i-1]){array[0] = array[i];for(j = i - 1 ; array[j] > array[0] ;--j)array[j + 1] = array[j];array[j + 1] = array[0];}} } (1)時間、空間復雜度
????? 插入排序雖然在最壞情況下復雜性為O(n2),但是對于小規模輸入來說,插入排序法是一個快速的排序法。從空間來看,它只需要一個元素的輔助空間,用于元素的位置交換O(1)。
(2)穩定性:
???? 插入排序是穩定的;因為具有同一值的元素必然插在具有同一值得前一個元素的后面,即相對次序不變。

四、簡單選擇排序
????? 簡單選擇排序的基本思想:第i趟簡單選擇排序是指通過n-i次關鍵字的比較,從n-i+1個記錄中選出關鍵字最小的記錄,并和第i個記錄進行交換。共需進行i-1趟比較,直到所有記錄排序完成為止。例如:進行第i趟選擇時,從當前候選記錄中選出關鍵字最小的k號記錄,并和第i個記錄進行交換。
實現代碼如下:
void SelectSort(int array[] , int length) // 簡單選擇排序 {int i , j , k;for(i = 0 ; i < length-1 ; ++i){k = i;for(j = i + 1 ; j < length ; ++j) // 從后面選擇一個最小的記錄{if(array[j] < array[k])k = j;}if(k != i) // 與第i個記錄交換swap(array[i] , array[k]);} }(1)關鍵字比較次數
???  無論文件初始狀態如何,在第i趟排序中選出最小關鍵字的記錄,需做n-i次比較,因此,總的比較次數為:
???? n(n-1)/2=0(n2)
(2)記錄的移動次數
???  當初始文件為正序時,移動次數為0
???  文件初態為反序時,每趟排序均要執行交換操作,總的移動次數取最大值3(n-1)。
???  直接選擇排序的平均時間復雜度為O(n2)。
(3)直接選擇排序是一個就地排序
(4)穩定性分析
???   直接選擇排序是不穩定的。
?? 【例】反例[2, 2,1]
五、歸并排序
void Merge(int array[] , int low , int mid , int high) {int i , j , k;int *temp = (int *)malloc((high - low + 1)*sizeof(int));i = low , j = mid + 1 , k = 0;while(i <= mid && j <= high){if(array[i] < array[j]) // 進行排序存入動態分配的數組中temp[k++] = array[i++];elsetemp[k++] = array[j++];}while(i <= mid) // 如果前一半中還有未處理完的數據,按順序移入動態分配的數組內temp[k++] = array[i++];while(j <= high) // 如果前一半中還有未處理完的數據,按順序移入動態分配的數組內temp[k++] = array[j++];for(i = low , j = 0; i<= high ; ++i)array[i] = temp[j++];free(temp); }void Msort(int array[] , int low , int high) {int mid;if(low < high){mid = (low + high)>>1;Msort(array , low , mid);Msort(array , mid + 1 , high);Merge(array , low , mid , high);} }
六、堆排序
void HeapAdjust(int array[] , int s , int m) // 對堆進行調整,使下標從s到m的無序序列成為一個大頂堆 {int j , temp = array[s];for(j = 2*s; j <= m ; j *= 2){if(j < m && array[j] < array[j + 1]) // 如果結點的左孩子小于右孩子增加j的值++j; // 用于記錄較大的結點的下標if(temp >= array[j]) // 如果父結點大于等于兩個孩子,則滿足大頂堆的定義,跳出循環break;array[s] = array[j]; // 否則用較大的結點替換父結點s = j; // 記錄下替換父結點的結點下標 }array[s] = temp; // 把原來的父結點移動到替換父結點的結點位置 }void HeapSort(int array[] , int len) {int i;for(i = len / 2; i >= 0 ; --i) // 建立大頂堆HeapAdjust(array , i , len-1);for(i = len - 1 ; i > 0 ; --i){swap(array[0] , array[i] ); // 第個元素和最后一個元素進行交換 HeapAdjust(array , 0 , i-1); // 建立大頂堆 } } 七、冒泡排序
// 將小元素冒泡到最前面,首先操作的是小元素 void Bubble_Sort1(int array[] , int len) {int i , j;for(i = 0 ; i < len - 1 ; ++i){for(j = i + 1 ; j < len ; ++j){if(array[j] < array[i])swap(array[i] , array[j] ); }} }// 將最大的元素冒泡到最后面 void Bubble_Sort2(int array[] , int len) {int i , j;for(i = 0 ; i < len ; ++i) //注意和上面的算法對照此循環{for(j = 0 ; j < len - 1 - i ; ++j){if(array[j] > array[j + 1])swap(array[j] , array[j+1] ); }} }// 雙向冒泡 void Bubble_Sort3(int array[] , int len) {int left , right , i;left = 0 , right = len - 1;while(left < right){for(i = left ; i < right ; ++i) // 從左到右冒泡{if(array[i + 1] < array[i])swap(array[i] , array[i+1]);}--right;for(i = right ; i > left ; --i) // 從右到左冒泡{if(array[i ] < array[i - 1])swap(array[i] , array[i-1]);}++left;} }





總結

以上是生活随笔為你收集整理的快速排序、希尔排序、插入排序、选择排序、归并排序、堆排序总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。