一個用來了解數據結構算法(各種排序,列表,樹等)很友好的網站:
https://visualgo.net/en
該題目來自于牛客:算法篇-排序問題
快排(必備)+歸并(體會分治)+堆(自己建堆)
//快速排序 關鍵在于 partition函數,可以自己參考一個模板,我這個參考大話數據結構class Solution {
public:/*** 代碼中的類名、方法名、參數名已經指定,請勿修改,直接返回方法規定的值即可* 將給定數組排序* @param arr int整型vector 待排序的數組* @return int整型vector*///1.快速排序vector<int> MySort(vector<int>& arr) {// write code hereint left=0;int right=arr.size()-1;QuickSort(arr,left,right);return arr;}int QuickTemp(vector<int>& arr,int left,int right){ int i = left;int j = right;int temp = arr[left];while(i<j){while(temp<=arr[j]&&i<j) --j;arr[i]=arr[j];while(temp>=arr[i]&&i<j) ++i;arr[j]=arr[i];}arr[i] = temp;return i;}void QuickSort(vector<int>& arr,int left,int right){if(left<right){int mid=QuickTemp(arr,left,right);QuickSort(arr, left,mid-1);QuickSort(arr, mid+1, right);}}
};//歸并排序 關鍵在于構造一個數組 然后merge,所以這個 merge函數是關鍵
class Solution {
public://歸并排序vector<int> MySort(vector<int>& arr) {MySortCore(arr,0,arr.size()-1);return arr;}void MySortCore(vector<int>&arr,int start,int end){if(start>=end) return;int middle=start+((end-start)>>1);MySortCore(arr,start,middle);MySortCore(arr,middle+1,end);Merge(arr,start,middle,end);}void Merge(vector<int>&arr,int start,int middle,int end){int* tmp=new int[end-start+1];int left=start;int right=middle+1;int pTmp=0; //輔助數組指針while(left<=middle && right<=end){if(arr[left]<arr[right])tmp[pTmp++]=arr[left++];elsetmp[pTmp++]=arr[right++];}while(left<=middle)tmp[pTmp++]=arr[left++];while(right<=end)tmp[pTmp++]=arr[right++];//排序完數組拷貝回原數組for(int i=0;i<end-start+1;i++)arr[start+i]=tmp[i];}
};
//堆排序,分為兩步,建堆+排序
//一些細節可以參考大話數據結構
//我這個堆是從下標為0開始的,所以左子節點 left=2*root+1, right=2*root+1class Solution {
public://堆排序void Swap(int&a,int &b){int tmp=a;a=b;b=tmp;}void HeapAdjust(vector<int>&arr,int root,int len){int tmp=arr[root];for(int j=2*root+1;j<len;j=2*j+1){if(j<len-1 && arr[j]<arr[j+1])++j;if(tmp>arr[j])break;arr[root]=arr[j];root=j;}arr[root]=tmp;}vector<int> MySort(vector<int>& arr) {for(int i=arr.size()/2-1;i>=0;i--)HeapAdjust(arr,i,arr.size());for(int i=arr.size()-1;i>0;i--){Swap(arr[0],arr[i]);HeapAdjust(arr,0,i);}return arr;}
};
小結:
在做快排序的時候,出現了超時問題,解決辦法:
1、邏輯調整
2、把i++/j–,替換成++i/–j。
3、使用遞歸前的函數傳參最好不是計算式。
以下是其他友友的代碼和注釋(寫的很認真就貼了過來):
class Solution {
public:/*** 代碼中的類名、方法名、參數名已經指定,請勿修改,直接返回方法規定的值即可* 將給定數組排序* @param arr int整型vector 待排序的數組* @return int整型vector*/vector<int> MySort(vector<int>& arr) {// write code heremySort1(arr);return arr;}// 1、快速排序(通過)// 時間復雜度O(logn)。空間復雜度是O(n)。// 主要是要找出標桿值(中間值),默認最后一個值為標桿值,然后比它小的放左邊,比他大的放右邊,然后交換最后一位。就得到標桿值在中間的下標。
// 樹,從上往下排序// 不穩定算法void mySort1(vector<int>& arr) {quicksort(arr, 0, arr.size()-1);} void quicksort(vector<int> &arr, int left, int right) {if (left > right) return;int pivotIndex = partition(arr, left, right); // 標桿值所在的位置quicksort(arr, left, pivotIndex-1); // 左半邊quicksort(arr, pivotIndex+1, right); // 右半邊}int partition(vector<int> &arr, int left, int right) {// 最后一個值當做標桿int counter = left; // 記錄小于標桿值的個數while (left < right) {if (arr[left] < arr[right]) { // 當前值和標桿值比較,決定是放在左邊還是右邊swap(arr[left], arr[counter]);counter++;}left++;}swap(arr[counter], arr[right]); // 最后把標桿值移到中間位置,然后返回下標。return counter;}// 2、歸并排序(通過)// 時間復雜度O(logn)。空間復雜度是O(n)。// 歸并排序是建立在歸并操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。// 樹,從下往上排序// 是穩定的算法void mySort2(vector<int>& arr) {mergeSort(arr, 0, arr.size()-1);} void mergeSort(vector<int> &arr, int left, int right) {if (left >= right) return;int mid = left + (right - left) / 2;mergeSort(arr, left, mid); // 遞歸 左半邊mergeSort(arr, mid+1, right); // 遞歸 右半邊merge(arr, left, mid, right); // 合并兩個有序的數組(參考合并兩個有序的鏈表)}// 合并兩個有序數組void merge(vector<int> &arr, int left, int mid, int right) {vector<int> tmp(right-left+1); // 開辟新的數組int i = left, j = mid+1, k = 0; // i左邊數組的起始位置,j右邊數組的起始位置,k已經放入新數組的個數while (i <= mid && j <= right) { // 比較左右數組,數值小的放入新數組中tmp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];}while (i <= mid) tmp[k++] = arr[i++]; // 如果左半邊數組沒有排序完,加入新數組while (j <= right) tmp[k++] = arr[j++]; // 如果右半邊數組沒有排序完,加入新數組for (i = left, k = 0; i <= right;) arr[i++] = tmp[k++]; // 新數組數據放回到原來的數組中}// 3、堆排序(通過)// 時間復雜度O(logn)。空間復雜度是O(n)。// 不穩定算法void heapSort(vector<int> &arr) {priority_queue<int,vector<int>,greater<int>> q; //小頂堆for (int i = 0; i < arr.size(); i++) {q.push(arr[i]);}for (int i = 0; i < arr.size(); i++) {arr[i] = q.top();q.pop();}}// 4、冒泡排序(超時)// 時間復雜度O(n2),空間復雜度O(1)// 從后往前排// 兩兩比較交換,最大的放在后面,穩定排序void bubbleSort(vector<int>& arr) {for (int i = 0; i < arr.size(); i++) {for (int j = 0; j < arr.size()-i-1; j++) {if (arr[j]>arr[j+1]) {swap(arr[j], arr[j+1]);}}}}// 5、選擇排序(超時)// 時間復雜度O(n2),空間復雜度O(1)// 從前往后排// 遍歷數組,找出最小值,最小的放在前面,不穩定排序void selectionSort(vector<int>& arr) {int minIndex = 0;for (int i = 0; i < arr.size(); i++) {minIndex = i;for (int j = i+1; j < arr.size(); j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}swap(arr[i], arr[minIndex]);}}// 6、插入排序(超時)// 時間復雜度O(n2),空間復雜度O(1)// 從前往后排// 遍歷數組,找出一個值,往排好的數組里面插入合適的位置。穩定排序void insetionSort(vector<int>& arr) {int preIndex = 0;int currentVal = 0;for (int i = 1; i < arr.size(); i++) {preIndex = i - 1;currentVal = arr[i];while (preIndex >= 0 && arr[preIndex] > currentVal) {arr[preIndex+1] = arr[preIndex];preIndex--;}arr[preIndex+1] = currentVal;}}};