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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

数据结构-王道-排序

發布時間:2025/3/15 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构-王道-排序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

排序

關于排序算法的視頻演示

直接插入排序

???? ??從上面的插入排序思想中,不難得到一種簡單直接的插入排序算法。假設待排序表在某次過程中屬于這種情況。
|有序序列\(L[1\ldots i-1]\)|L(i)|無序序列\(L[i+1\ldots n]\)|
|:-|:-|

???? ??為了實現將元素\(L(i)\)插入到已有序的子序列\(L[1\ldots i-1]\)中,我們需要執行以下操作(為了避免混淆,下面用\(L[]\)表示一個表,而用\(L()\)表示一個元素):

  • 查找出\(L(i)\)\(L[i+1\ldots n]\)中的插入位置k。
  • \(L[k\ldots i-1]\)中所有元素全部后移一個位置。
  • \(L(i)\)賦值到\(L(k)\)
  • void InserSort(int A[],int n) {int i,j;for(i=2;i<=n;i++){if(A[i]<A[i-1]){A[0]=A[i];for(j=i-1;A[0]<A[j];j--)A[j+1]=A[j];A[j+1]=A[0];}} }

    折半插入排序

    ???? ??從前面的直接插入排序算法中,不難看出每趟插入的過程,都進行了兩項工作:

  • 從前面的子表中查找出待插入元素應該被插入的位置。
  • 給插入位置騰出空間,將待插入元素復制到表中的插入位置。
  • 注意到該算法中,總是邊比較邊移動元素,下面將比較和移動操作分離開,即先折半查找出元素的待插入位置,然后再同意的移動待插入位置之后的元素。

    void InserSort(int A[],int n) {int i,j,low,high,mid;for(i=2;i<=n;i++){A[0]=A[i];low=1,high=i-1;while(low<=high){mid=(low+high)/2;if(A[mid]>A[0])high=mid-1;elselow=mid+1;}for(j=i-1;j>=high+1;j--)A[j+1]=A[j];A[high+1]=A[0];} }

    折半插入排序

    ???? ??從前面的代碼原理中不難看出,直接插入排序適用于基本有序的排序表和數據量不大的排序表。1959年\(D.L.Shell\)提出了希爾排序,又稱為縮小增量排序
    ???? ??希爾排序的基本思想是:先將待排序表分割為若干個形如\(L[i,i+d,i+2d,\ldots,i+kd]\)特殊子表,分別進行直接插入排序。希爾排序的排序過程如下:
    ???? ??先取一個小于n的步長d1,把表中全部記錄分為\(d_1\),所有距離為\(d_1\)的倍數的記錄放在同一個組中,在各組中進行直接插入排序;然后取第二個步長\(d_2\leq d_1\),重復上述過程,直到所取到的\(d_t=1\),即所有記錄已放在同一組中,再進行直接插入排序,由于此時已經具有較好的局部有序性,故可以很快的得到結果。到目前為止,尚未求得一個最好的增量序列,希爾提出的方法是\(d_1=\frac n 2\)\(d_{i+1}= \frac {d_i} 2\),并且最后一個增量等于1。

    void SheelSort(int A[],int n) {for(int dk=n/2;dk>=1;dk=dk/2)for(int i=dk+1;i<=n;i++)if(A[i]<A[i-dk]){A[0]=A[i];for(int j=i-dk;j>0&&A[0];j=j-dk)A[j+dk]=A[j];A[j+dk]=A[0];} }

    冒泡排序

    ???? ??冒泡排序的算法思想是:假設待排序表長為n,從后往前(或者從前向后)兩兩比較相鄰元素的值,若為逆序(即\(A[i-1]>A[i]\)),則交換他們,知道序列比較完。我們稱之為一趟冒泡,結果將最小的元素交換到待排序的第一個位置(關鍵字最小的元素如氣泡一般逐漸向上“漂浮”直至“水面”,這就是冒泡排序名字的由來)。下一趟冒泡的時候,前一趟確定的最小元素不再參加比較,待排序列減少一個元素,每趟冒泡的結果把序列中的最小元素放到了序列的最終位置。

    void BuuleSort(int A[],int n) {for(int i=0;i<n-1;i++){bool flag=false;for(int j=n-1;j>i;j--)if(A[j-1]>A[j]){swap(A[j-1],A[j]);flag=true;}if(flag==false)break;} }

    快速排序

    ???? ??快速排序是對冒泡排序的一種改進,其基本思想是基于分治法的:在待排序表\(L[1\ldots n]\)中任取一個元素pivot作為基準,通過一趟排序將待排序表劃分為獨立的兩部分\(L[1\ldots k-1]\)\(L[k+1\ldots n]\)使得\(L[1\ldots k-1]\)中所有元素小于pivot,\(L[k+1\ldots n]\)中所有元素均大于或等于pivot,則pivot放在了其最終位置\(L(k)\)上,這個過程稱為一趟快速排序。而后分別遞歸的對兩個子表重復上述過程,直至每部分內只有一個元素或者為空為止,即所有元素放在了其最終位置之上。
    ???? ??首先假設劃分算法已知,記為\(Partition()\),返回的是上述的k,注意到\(L(k)\)已經在最終的位置,所以可以先對表進行劃分,而后對兩個表調用同樣的排序操作。因此可以遞歸的調用快速排序算法進行排序,具體的程序結構如下:

    int Partition(int A[],int low,int high) // 傳入 數組和 上下限 {int pivot = A[low]; // 讓pivot暫存傳入的數組第一個值.while(low<high) // 當low等于high的時候 才跳出去。{while(low<high&&A[high]>=pivot) // 當low小于high并且數組靠前的值high--; //開始 減小high的值 知道不符合上述條件A[low]=A[high]; // 較小的值 放到前面 那個空位上while(low<high&&A[low]<=pivot) // 當low小于high并且數組靠前的值比較小low++;A[high]=A[low];}A[low]=pivot;return low; } void QuickSort(int A[],int low,int high) {if(low<high){int pivot = Partition(A,low,high);QuickSort(A,low,pivot-1);QuickSort(A,pivot+1,high);} }

    簡單選擇排序

    ???? ??從上面選擇排序的思想中可以很直觀的得出簡單選擇排序算法的思想:假設排序表\(L[1\ldots n]\),第i趟排序即從\(L[i\ldots n]\)中選擇關鍵字最小的元素與\(L(i)\)交換,每一趟排序可以確定 一個元素的最終位置,這樣經過\(n-1\)趟排序就可以使整個排序表有序。

    void SelectSort(int A[],int n) {for(int i=0;i<n-1;i++){int Min=i;for(int j=i+1;j<n;j++)if(A[j]<A[Min])Min=j;if(Min!=i)swap(A[i],A[Min]);} }

    堆排序

    ???? ??堆排序是一種樹形選擇排序方法,它的特點是:在排序過程中,將\(L[1\ldots n]\)看做一棵完全二叉樹的順序存儲結構,利用完全二叉樹雙親結點和孩子結點之間的內在關系,在當前無序區中選擇關鍵字最大。
    ???? ??堆的定義如下:n個關鍵字序列\(L[1\ldots n]\)稱為堆,當且僅當該序列滿足:\(L(i)\leq L(2i)\)\(L(i)\leq L(2i+1)\)\(L(i)\geq L(2i)\)\(L(i)\geq L(2i+1)\)
    滿足前者的稱為小根堆(小頂堆),滿足后者情況的堆稱為大根堆(大頂堆)。顯然,在大根堆中,最大元素存放在根節點中,且對其任一費根節點,它的值小于或者等于其雙親結點值。小根堆的定義剛好相反,根節點是最小元素。下圖所示為一個大根堆。



    ???? ??堆排序的關鍵是構造初始堆,對初始序列建堆,就是一個反復篩選的過程。n個結點的完全二叉樹,最后一個結點是第\([\frac n 2]\)個結點為根的子樹篩選(對于大根堆,若根節點的關鍵字小于左右子女中較大者,則交換),使該子樹成為堆。之后向前依次對各結點\(([\frac n 2]-1 \rightarrow 1)\)為根的子樹進行篩選,看該節點值是否大于其左右子結點的值,若不是,將左右子結點中較大值與之交換,交換后可能會破壞下一級的堆,遇事繼續采用上述方法構造下一級的堆,直到以該節點為根的子樹構成堆為止。反復利用上述調整對的方法建立堆,知道根節點。過程如下圖所示: void AdjustDown(int A[],int k,int len) {A[0]=A[k];for(int i=2*k;i<=len;i=i*2){if(i<len&&A[i]<A[i+1])i++;if(A[0]>=A[i])break;else{A[k]=A[i];k=i;}}A[k]=A[0]; } void AdjustUp(int A[],int k) {A[0]=A[k];int i=k/2;while(i>0&&A[i]<A[0]){A[k]=A[i];k=i;i=k/2;}A[k]=A[0];} void BuildMaxHeap(int A[],int len) {for(int i=len/2;i>0;i--)AdjustDown(A,i,len);//AdjustUp(A,i); } void HeapSort(int A[],int len) {BuildMaxHeap(A,len);for(int i=len;i>1;i--){swap(A[i],A[1]);AdjustDown(A,1,i-1);} }

    ???? ??向下調整的時間和樹的高度有關,為\(O(h)\)。建堆過程中每次向下調整時,大部分結點的高度都比較小。因此,可以證明在元素個數為n的序列上建堆,其時間復雜度\(O(n)\),這說明可以在線性時間內,將一個無需數組建立成一個大頂堆。
    ???? ??應用堆這種數據結構進行排序的思路很簡單,首先將存放在\(L[1\ldots n]\)中的n個元素簡稱初始堆,由于堆本身的特點(以大頂堆)為例,堆頂元素就是最大值,輸出堆頂元素后,通常將堆低元素送入堆頂,此時根節點已經不滿足于大頂堆的性質,堆被破壞,將對頂元素向下調整使其繼續保持大頂堆的性質,再輸出堆頂元素。如此重復,直到堆中僅剩下一個元素為止。

    歸并排序

    ???? ??歸并排序和上述基于交換,選擇等排序思想不一樣,“歸并”的含義是將兩個或者兩個以上的有序表組合為一個新的有序表。假定待排序表中含有n個記錄,則可以看為是n個有序的子表,每個子表長度為1,然后兩兩歸并,得到\([\frac n 2]\)個長度為2或者1的有序表;再兩兩歸并,如此這般 重復歸并,知道合并為一個長度為n的有序表為止,這種排序方法稱為2-路歸并排序。



    ???? ??\(Merge()\)的功能是將前后相鄰的兩個有序表歸并為一個有序表的算法。設兩段有序表\(A[low\ldots mid]\)\(A[mid+1\ldots high]\)存放在同一順序表中相鄰的位置上,先將他們復制到輔助數組B中。每次從對應B中的兩段去除一個記錄進行關鍵字的比較,將較小者放入A中,當數組B中有一段的下標超過其對應的表長時(即改段的所有元素已經完全復制到A中),將另一段中的剩余部分直接復制到A中。

    轉載于:https://www.cnblogs.com/A-FM/p/9707162.html

    總結

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

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