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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

排序详解

發布時間:2024/4/11 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 排序详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

排序詳解

文章目錄

  • 排序詳解
    • **一、選擇排序**
    • **二、插入排序**
    • **三、希爾排序**
    • **四、堆排**
    • 五、冒泡排序:
    • **六、快速排序hoare版本**
    • **七、快速排序 挖坑法**
    • **八、快速排序前后指針版本**
    • 九、快速排序優化--三數取中
    • 十、快速排序----小區間優化
    • 十一、快速排序非遞歸版:
    • 十二、歸并排序:

一、選擇排序

代碼:

void SelectSort(int* arr,int len) {int begin = 0;int end = len - 1;while(begin < end){int min_index = begin;int max_index = end;for(int i = begin;i <= end;i++){if(arr[i] > arr[max_index]){max_index = i;}if(arr[i] < arr[min_index]){min_index = i;}}Swap(&arr[begin],&arr[min_index]);//交換的時候需要注意,如果最大值剛好在begin位置處,經過前面的交換,最大值已經杯換到最小下標處if(max_index == begin){max_index = min_index; }Swap(&arr[end],&arr[max_index]); begin++;end--;} }


思想:

  • 上述代碼的選擇排序是先定義兩個下標min_index,和max_index,用來記錄每趟比較中最小元素和最大元素的下標
  • 然后在循環內部進行選擇記錄,每趟循環結束min_index和max_index已經記錄該趟的最大元素和最小元素的下標,
  • 然后進行交換,把最小的元素交換到數組的begin位置處,最大的元素交換到end位置處,
  • 注意??在交換完最小元素后需要進行判斷,因為如果剛好最大元素就是在begin位置處,那么后序要交換最大元素到end位置處就會出錯,因為如果最大元素在begin的情況下,經過前面的交換,現在最大元素的位置應該在min_index下標處,所以應更新最大元素位置的下標
  • 在元素集合array[i]–array[n-1]中選擇關鍵碼最大(小)的數據元素
  • 若它不是這組元素中的最后一個(第一個)元素,則將它與這組元素中的最后一個(第一個)元素交換
  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重復上述步驟,直到集合剩余1個元素

二、插入排序

代碼:

void InsertSort(int* arr,int len) {int end = 0;for(end =0 ;end < len -1;end ++){int temp = arr[end +1];while(end >= 0){if(arr[end] > temp){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = temp; } }


思想:

  • 先定義end來標識有序序列的最后一個元素的下標,
  • 再把end后的第一個元素temp往有序序列內插
  • 如果temp比end位置元素大,就直接往end+1位置放temp即可
  • 如果temp比end位置元素小,就把end位置元素放到end+1位置處,繼續循環向前判斷
  • 元素集合越接近有序,直接插入排序算法的時間效率越高
  • 時間復雜度:O(N^2)
  • 空間復雜度:O(1),它是一種穩定的排序算法
  • 穩定性:穩定
  • 當插入第i(i>=1)個元素時,前面的array[0],array[1],…,array[i-1]已經排好序,此時用array[i]的排序碼與
    array[i-1],array[i-2],…的排序碼順序進行比較,找到插入位置即將array[i]插入,原來位置上的元素順序后移

三、希爾排序

代碼:

void ShellSort(int* arr,int len) {int gap = len;while(gap > 1){gap = gap / 3 +1;for(int i = 0;i < len - gap;i++){int end = i;int temp = arr[end + gap];while(end >= 0){if(arr[end] > temp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = temp;}} }


思想:

  • 定義一個gap為分得的組數,gap越大越不接近有序,所以gap應是動態變化的,直到為1,就是插入排序
  • 希爾排序法又稱縮小增量法。希爾排序法的基本思想是:先選定一個整數,把待排序文件中所有記錄分成個
    組,所有距離為的記錄分在同一組內,并對每一組內的記錄進行排序。然后,取,重復上述分組和排序的工
    作。當到達=1時,所有記錄在統一組內排好序
  • 希爾排序的時間復雜度不好計算,需要進行推導,推導出來平均時間復雜度: O(N1.3—N2)
  • 穩定性:不穩定

四、堆排

代碼:

//向下調整 void adjust(int* arr,int len,int index) {int parent = index;int child = parent * 2 + 1;while(child < len){if(child + 1 < len && arr[child] < arr[child + 1]){child = child + 1;}if(arr[child] > arr[parent]){Swap(&arr[child],&arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}} }//堆排 void HeapSort(int* arr,int len) {for(int i = (len - 1 - 1 ) / 2;i >= 0;i--){adjust(arr, len, i);}int end = len - 1;while(end > 0){Swap(&arr[0],&arr[end]);adjust(arr,end,0);end--;} }


思想:

  • 堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。它是通過堆來進行選擇數據。需要注意的是排升序要建大堆,排降序建小堆
  • 注意向下調整算法的寫法,首先從倒數第一個非葉子節點開始調整,把整棵樹調整為大根堆
  • 建大堆使,取左右兩個孩子中較大的和父親節點比較,看是否需要交換,直到把整棵樹調整為大根堆
  • 排序的過程就是把堆頂元素和數組的最后一個元素進行交換,再次進行向下調整,注意此時,交換過來的堆頂元素就相當于是有序的,再次進行向下調整時就把數組的元素個數-1,一次類推,循環排序
  • 堆排序使用堆來選數,效率就高了很多。
  • 時間復雜度:O(N*logN)
  • 空間復雜度:O(1)
  • 穩定性:不穩定

五、冒泡排序:

這個比較簡單,直接來代碼:

void bubbleSort(int *str, int len) { //冒泡排序, 升序排列 //數組當中比較小的數值向下沉,數值比較大的向上浮!int i = 0;//趟數int flg ;for(i = 0;i < len-1;i++){int j = 0;//次數flg = 0;//如果第一次已經是排序好了,就不用排序了,直接brekfor(j = 0;j < len-1-i;j++){if(str[j] > str[j+1]){int tmp = str[j];str[j] = str[j+1];str[j+1] = tmp;flg = 1;}}if(!flg){break;}} }

六、快速排序hoare版本

int QuickSortChild1(int* arr,int begin,int end) {int key = begin;while(begin < end){while(begin < end && arr[end] >= arr[key]){end--;}while(begin < end && arr[begin] <= arr[key]){begin++;}Swap(&arr[end],&arr[begin]);}Swap(&arr[key],&arr[begin]); return begin; }//快排 void QuickSort(int* arr,int begin,int end) {//注意遞歸出口if(begin < end){int mid = QuickSortChild1(arr,begin,end);QuickSort(arr,begin,mid - 1);QuickSort(arr,mid + 1,end);} }

七、快速排序 挖坑法

int QuickSortChild2(int* arr,int begin,int end) {int key =arr[begin];while(begin < end){while(begin < end && arr[end] >= key){end--;}arr[begin] = arr[end];while(begin < end && arr[begin] <= key){begin++;}arr[end] = arr[begin];}arr[begin] = key;return begin; } void QuickSort(int* arr,int begin,int end) {//注意遞歸出口if(begin < end){int mid = QuickSortChild2(arr,begin,end);QuickSort(arr,begin,mid - 1);QuickSort(arr,mid + 1,end);} }

八、快速排序前后指針版本

//雙指針法 int QuickSortChild3(int* arr,int begin,int end) {int pref = begin - 1;int cur = begin;int key = end;//定義pref,cur 。pref指向cur的前一個while(cur < end){//cur去找比key小的元素,如果找到,就把pref++,就交換cur和pref下標所在的元素if(arr[cur] < arr[key]){pref++;Swap(&arr[cur],&arr[pref]);}//如果cur所在下標的元素比key所在元素大,就直接后移curcur++;}//最后注意和end位置的元素交換的是pref的下一個,不是它自己Swap(&arr[++pref],&arr[end]);return pref; } void QuickSort(int* arr,int begin,int end) {//注意遞歸出口if(begin < end){int mid = QuickSortChild3(arr,begin,end);QuickSort(arr,begin,mid - 1);QuickSort(arr,mid + 1,end);} }


注意:雙指針法是用cur去找比key小的元素,如果找到就把pref++,交換Swap(&arr[cur],&arr[pref]);繼續循環,最后注意不是拿pref和key進行交換,而是拿pref的下一個和key進行交換Swap(&arr[++pref],&arr[end]);

九、快速排序優化–三數取中

//快排優化--->三數取中,防止有序的情況 void medianOfThree(int* arr,int begin,int end) {int mid = (begin + end) >> 1;if(arr[mid] > arr[begin]){Swap(&arr[mid],&arr[begin]);}if(arr[mid] > arr[end]){Swap(&arr[mid],&arr[end]);}if(arr[end] < arr[begin]){Swap(&arr[end],&arr[begin]);} } void QuickSort(int* arr,int begin,int end) {//注意遞歸出口if(begin < end){medianOfThree(arr,begin,end);int mid = QuickSortChild3(arr,begin,end);QuickSort(arr,begin,mid - 1);QuickSort(arr,mid + 1,end);} }

十、快速排序----小區間優化

//快排優化--->小區間優化 + 三數取中 void QuickSort2(int* arr,int begin,int end) {if(begin < end){//小區間就直接使用選擇排序,注意邊界條件的控制if(end - begin + 1 < 10){SelectSort(arr + begin,end - begin + 1);}else{medianOfThree(arr,begin,end);int mid = QuickSortChild3(arr,begin,end);QuickSort1(arr,begin,mid - 1);QuickSort1(arr,mid + 1,end);}} }

十一、快速排序非遞歸版:

void QuickSort(int* arr,int left,int right) {stack<int> s;s.push(left);s.push(right);while(!s.empty()){int end = s.top();s.pop();int begin = s.top();s.pop();int mid = QuickChild(arr,begin,end);//cout<<"i am quicksort"<<endl;if(begin < mid - 1){s.push(begin);s.push(mid - 1);}if(mid + 1 < end){s.push(mid + 1);s.push(end);}}for(int i = 0;i <= right;i++){cout<<arr[i]<<" < ";}cout<<endl; }

十二、歸并排序:

//歸并排序 void MergeSortChild(int* arr,int begin,int end,int* temp) {if(begin == end){return ;}int mid = (begin + end) >> 1;MergeSortChild(arr,begin,mid,temp);MergeSortChild(arr,mid + 1,end,temp);int begin1 = begin;int end1 = mid;int begin2 = mid + 1;int end2 = end;int index = begin;while(begin1 <= end1 && begin2 <= end2 ){if(arr[begin1] < arr[begin2]){temp[index] = arr[begin1];index++;begin1++;}else {temp[index] = arr[begin2];index++;begin2++;}}while(begin1 <= end1){temp[index] = arr[begin1];index++;begin1++;}while(begin2 <= end2){temp[index] = arr[begin2];index++;begin2++;}memcpy(arr + begin,temp + begin,sizeof(int) * (end - begin + 1)); }void MergeSort(int* arr,int n) {int* temp = (int*)malloc(sizeof(int) * n);MergeSortChild(arr,0,n - 1,temp); }


基本思想:

  • 歸并排序(MERGE-SORT)是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and
    Conquer)的一個非常典型的應用。將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有
    序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。 歸并排序核心步驟

  • 歸并的缺點在于需要O(N)的空間復雜度,歸并排序的思考更多的是解決在磁盤中的外排序問題。

  • 時間復雜度:O(N*logN)

  • 空間復雜度:O(N)

  • 穩定性:穩定

總結

以上是生活随笔為你收集整理的排序详解的全部內容,希望文章能夠幫你解決所遇到的問題。

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