1. 程式人生 > >資料結構(14)——插入排序、交換排序、選擇排序、歸併排序和基數排序演算法的比較

資料結構(14)——插入排序、交換排序、選擇排序、歸併排序和基數排序演算法的比較

在排序過程中依據不同原則對內部排序方法進行分類,可大致分為插入排序、交換排序、選擇排序、歸併排序和基數排序等五類

插入排序

直接插入排序

直接插入排序市一中最簡單的排序方法,它的基本操作是將一個記錄插入到已排好序的有序表中,從而得到一個新的有序表

void InsertSort(SqList &L)
{
for(int i=2;i<L.length;i++)
    if(LT(L.r[i].key,L.r[i-1].key))
                            //若L.r[i].key<L.r[i-1].key則需將L.r
[i]插入有序表中 { L.r[0]=L.r[i]; //複製哨兵 for(int j=i-1;LT(L.r[0].key,L.r[j].key);--j) L.r[j+1]=L.r[j]; //記錄後移 L.r[j+1]=L.r[0]; //插入至正確位置 } }//InsertSort

折半插入排序

——穩定的排序方法

 void BInsertSort( SqList &L) {
     for ( i = 2; i< L.length; ++i) {
       L.r[0] = L.r[i];                  // 將L.r[i]暫存在L.r[0] 
low=1; high= i-1; while ( low<=high) { // 在r[low.. High]中折半查詢有序插入的位置 m = (low +high)/2; // 折半 if LT( L.r[0].key, L.r[m].key) high= m-1; // 插入點在低半區 else low=m+1; //插入點在高半區 }//while
for(j=i-1; j>=high+1; --j) L.r[j+1]=L.r[j]; // 記錄後移 L.r[high+1]=L.r[0]; // 插入 } //for }// BInsertSort

希爾排序

——不穩定的排序方法

希爾排序又稱“縮小增量排序”,先將整個待排記錄序列分割成若干自序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對整體進行一次直接插入排序

快速排序

氣泡排序

——穩定的排序方法

首先將第一個記錄的關鍵字和第二個記錄的關鍵字進行
比較,若為逆序(即L.r[1].key>L.r[2].key),則將兩個記錄交換之,
然後比較第二個記錄和第三個記錄的關鍵字。依次類推,直至第n-1
個記錄和第n個記錄的關鍵字進行過比較為止。上述過程稱作第一
趟起泡排序,其結果使得關鍵字最大的記錄被安置到最後一個記錄
的位置上。然後進行第二趟排序,對前n-1個記錄進行同樣操作,其
結果是使關鍵字次大的記錄被安置到第n-1個記錄的位置上

void  bubblesort (SqList &L){
                    //對順序表 L 做起泡排序
    for ( i = n-1, change = TRUE; i >= 1&& change; --i){
                    //在 0..i 的範圍內將第 n-i 大的元素起泡至位置 i
        change = FALSE;
        for ( j = 0; j < i; ++j)
            if ( L.r[j].key > L.r[j+1].key)
            {L.r[j] <-> L.r[j+1]; change = TRUE;}
    }//for-i
}//bubblesort

快速排序

——不穩定的排序方法

通過一趟快速劃分經待排記錄分割成兩個獨立的部分,其中一部分的關鍵字均比另一部分的關鍵字小,重複以上步驟,以達到整個序列有序

int Partition( SqList  &L, int low, int high ) {
    // 交換順序表L中子表L.r[low.. high]的記錄,使樞軸記錄到位,並返回其所在位置,此時,在它之前(後)的記錄均不大(小)於它。
    L.r[0] = L.r[low];   // 用子表的第一個記錄作樞軸記錄
     pivotkey = L.r[low].key; 
    while ( low<high) {
        while ( low<high && L.r[high].key >=pivotkey) --high;
       if (low<high)    L.r[low] = L.r[high];
        while ( low<high && L.r[low].key<=pivotkey)  ++low;
        if (low<high)   L.r[high] = L.r[low];
    }
    L.r[low] = L.r[0];      // 樞軸記錄到位
    reutrn low;              // 返回樞軸所在位置
 } // Partiton

選擇排序

簡單選擇排序

——穩定排序

通過 n-i 次關鍵字間的比較,從n-i+1個記錄中選出關鍵字最小的記錄,並和第i (1<=i<=n) 交換之

void  SelectSort( SqList  &L) {
       // 對順序表L作簡單選擇排序
  for( i = 1;  i<L.length; ++i ) {
          j = SelectMinKey( L, i);   //選擇key值最小的記錄
   if ( i!=j)  L. r[i]  < — > L.r[j];
       }//for
  } //SelectSort

堆排序

——不穩定的排序方法

只需要一個記錄大小的輔助空間,每個待排序的記錄僅佔用一個儲存空間
堆的定義:完全二叉樹中所有非葉子節點的值均不大於(或均不小於)其左右孩子節點的值

 typedef  SqList   HeapType;      // 堆採用順序表儲存表示
 void  HeapAdjust( HeapType   &H, int s,  int  m) {
   //已知H.r[s..m]中記錄的關鍵字除H.r[s].key之外均滿足堆的定義,本函式調整H.r[s]的關鍵字,使H.r[s..m]成為一個大頂堆(對其中記錄的關鍵字而言)。
   rc = H.r[s];
   for ( j = 2*s; j<=m; j*=2) {      // 沿key較大的孩子結點向下篩選
      if ( j<m  && LT( H.r[j].key, H.r[j+1].key) ) ++j; 
                                     // j 為左右子 key 較大的記錄的下標
      if ( !LT( rc.key, H.r[j].key) )  break;   // rc應插入在位置s上
      H.r[s] = H.r[j]; s = j;
   }
   H.r[s] = rc;             // 插入
} // HeapAdjust

void  HeapSort( HeapType   &H) {
     // 對順序表H進行堆排序。
    for ( i= H.length/2; i>0; --i)     // 把H.r[1.. H.length]建成大頂堆
        HeapAdjust ( H, i, H.length );
    for ( i = H.length; i>1; --i){
        H.r[1]<->H.r[i];              // 將堆頂記錄和當前未經排序子序列
                                      // H.r[1.. i] 中最後一個記錄相互交換
        HeapAdjust( H, 1, i-1);   // 將 H.r[1.. i-1]
    }
 } // HeapSort

歸併排序

“歸併”的含義 是將兩個或兩個以上的有序表組合成一個新的有序表

2-路歸併排序

——穩定的排序方法

2-路歸併排序:假設初始序列含有n個記錄,則可看成是n個有序
的子序列,每個子序列的長度為1,然後兩兩歸併,得到 個
長度為2或1的有序子序列;再兩兩歸併,… …,如此重複,直至得
到一個長度為n的有序序列為止

鏈式基數排序

基數排序是一種藉助 “分配” 和 “收集” 兩種操作對單邏輯關鍵字
進行排序的一種內排方法。
其思想方法是:假設按 LSD 進行排序,
1、從最低位關鍵字起,按關鍵字的不同值( RADIX 個)將序列中記錄 “分配” 到 RADIX 個鏈佇列中;
2、再 “收集” 之:按該位關鍵字從小到大順序將 RADIX 個鏈隊
列首尾連線;
3、重複1,2步 d 次。
按這種方法實現排序稱之為基數排序,其中 “基” 指的是 RADIX
的取值範圍

幾種排序方法的討論

排序方法 | 平均時間
——————————
簡單排序 | O( n2 )
——————————
快速排序 |O( n log n )
——————————
堆排序 | O( n log n )
——————————
歸併排序 | O( n log n )
——————————
基數排序 | O ( d( n + rd ) )

平均時間效能

快排最佳,所需時間最省,但在最壞情況下的時間效能不如堆排序和歸併排序。而後兩者相比較結果是,在N較大時,歸併排序所需時間較省,但所需輔助儲存量大

簡單性

包括除希爾排序之外的所有插入排序,氣泡排序和簡單選擇排序,其中以直接插入排序最為簡單

時間複雜度

技術排序的時間複雜度可以寫成O(d*n),因此,它適合用於n值很大而關鍵字較小的序列

穩定性

所有時間複雜度為O(n^2)的簡單排序法都是穩定的,而快排、堆排序和希爾排序等時間效能較好的排序方法都是不穩定的

相關推薦

資料結構14——插入排序交換排序選擇排序歸併排序基數排序演算法比較

在排序過程中依據不同原則對內部排序方法進行分類,可大致分為插入排序、交換排序、選擇排序、歸併排序和基數排序等五類 插入排序 直接插入排序 直接插入排序市一中最簡單的排序方法,它的基本操作是將一個記錄插入到已排好序的有序表中,從而得到一

資料結構14線性表之C++實現一元多項式相乘

導言 原始碼實現 結果展示 導言 兩個一元多項式相乘的演算法,可以利用兩個一元多項式相加的演算法來實現,因為乘法可以分解為一系列的加法運算。 原始碼實現 #define OK 1 #defin

2018.9.14資料結構氣泡排序

/****************************************************   @Title: 資料結構實驗   @Name: <實驗1-1> 起泡排序   @Object:      [實驗目的]         把起泡排序的演算

挖掘演算法中的資料結構:堆排序之 二叉堆Heapify原地堆排序優化

不同於前面幾篇O(n^2)或O(n*logn)排序演算法,此篇文章將講解另一個排序演算法——堆排序,也是此係列的第一個資料結構—–堆,需要注意的是在堆結構中排序是次要的,重要的是堆結構及衍生出來的資料結構問題,排序只是堆應用之一。 此篇涉及的知識點有: 堆

基礎演算法資料結構字首中綴字尾表示式

目錄 簡介 字首表示式計算 字尾表示式計算 簡介 中綴表示式(正常的表示式) \[ (1+2)*3-4 \] 字首表示式(運算子位於運算元之前) \[ -*+1234 \] 字尾表示式(運算子位於運算元之後) \[ 12+3*4- \] 字首表示式計算 從右向左遍歷,

再談資料結構排序與查詢

1 - 引言 雖然C++中的STL庫中提供了許多排序和查詢的方法。但是我們還是需要了解一下排序和查詢內部的原理,下面讓我們學習一下各類排序與查詢演算法 2 - 歸併排序 第一種高效的排序演算法是歸併排序,按照分治三步法,對歸併排序演算法介紹如下: 劃分問題:把序列分成

資料結構 交換排序

最近只看了冒泡和快排這兩個演算法,今天面試就讓寫排序,用電腦寫,一去就讓寫程式碼,賊慌,然後面試官小姐姐真的賊好看,就是和麵試官小哥談論我的簡歷,坐在我對面,看著我寫程式碼真的賊慌。。一開始本來想寫快排,因為緊張,大腦短路,滿腦子都在冒泡泡。。最後還是寫了冒泡,,這裡再回顧一

資料結構——佇列及實現迴圈佇列實現

一、佇列    佇列是一種特殊的線性表,它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。佇列中沒有元素時,稱為空佇

小朋友學資料結構1:約瑟夫環的連結串列解法陣列解法數學公式解法

約瑟夫環(Josephus)問題是由古羅馬的史學家約瑟夫(Josephus)提出的,他參加並記錄了公元66—70年猶太人反抗羅馬的起義。約瑟夫作為一個將軍,設法守住了裘達伯特城達47天之久,在城市淪陷之後,他和40名死硬的將士在附近的一個洞穴中避難。在那裡,這些

從零開始_學_資料結構——STLmapsetlistvector

STL容器 前注: STL(標準模板庫)是一個C++的軟體庫,也是C++標準程式庫的一部分。 這些容器,應該都是STL裡面的一個類。 vector封裝陣列、list封裝連結串列、map和set封裝二叉樹 一、list 在不懂的時候,list可以理解為雙向連結串列(很像,

資料結構——二叉樹 前序中序後序層次遍歷及非遞迴實現 查詢統計個數比較求深度的遞迴實現

一、基本概念每個結點最多有兩棵子樹,左子樹和右子樹,次序不可以顛倒。性質:1、非空二叉樹的第n層上至多有2^(n-1)個元素。2、深度為h的二叉樹至多有2^h-1個結點。滿二叉樹:所有終端都在同一層次,

資料結構java——單鏈表雙端連結串列雙向連結串列

單鏈表    連結串列大家都很熟悉,連結串列是由若干個節點串起來的一個結構。類似於火車一樣,擁有一個頭結點(火車頭)之後掛著一個個的節點,每個節點後面跟上另一個節點。每個節點分為兩個域,一個數據域,用來存放這個節點的資料,一個是節點域,用來存放下一個節點。    所以對於單鏈

資料結構二叉樹節點空指標刪除葉節點最大節點數

1、二叉樹節點 程式碼: //二叉樹節點 #include<stdio.h> #include <malloc.h> #include <conio.h> #include<iostream> // typedef int

資料結構:非線性邏輯結構-特殊的二叉樹結構:堆哈夫曼樹二叉搜尋樹平衡二叉搜尋樹紅黑樹線索二叉樹

/* 性質1. 節點是紅色或黑色 性質2. 根是黑色 性質3. 每個紅色節點的兩個子節點都是黑色 (從每個葉子到根的所有路徑上不能有兩個連續的紅色節點) 性質4. 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點 */ #include #include typedef enum

演算法資料結構2:時間複雜度——以歸併排序為例

這一篇文章我們首先會介紹一下歸併排序,並以歸併排序和我們上一章所說的插入排序為例,介紹時間複雜度。此係列的所有程式碼均可在我的 [github](https://github.com/AlbertShenC/Algorithm) 上找到。 [點此](https://github.com/AlbertShen

演算法資料結構4:堆排序

堆排序(HeapSort)是最常用的排序演算法之一。這種排序演算法同時具有插入排序和歸併排序的優點。與插入排序一樣,具有**空間原址性**,即**任何時候都只需要常數個額外的空間儲存臨時資料**(對此,請大家回想一下歸併排序,隨著問題規模的越大,需要的額外空間就越大,在解決大型問題時,這是不可接受的缺點)。與

JavaScript 資料結構: 連結串列

前言 從實用性角度來說,連結串列對Javascript 來說沒有任何價值,為什麼呢? 我們先了解連結串列的特性,這個特性我們放在c++前提下來說,因為 這個特性是 根據 記憶體特性 來闡述的,Javascript 不存在記憶體操作,所有資料型別,本質性繼承Object 物件,而Ob

資料結構

***********************特殊的線性表-------棧**************************** 棧: 先進後出、後進先出 棧的插入運算 叫做入棧 棧的刪除運算 叫做出棧 演示程式碼: package com.chapter11; //棧的介面public int

資料結構:線性表

一、線性表及其邏輯結構 1、線性表的定義 線性表是具有相同特性的資料元素的一個有限序列。 該序列中所含的元素個數叫做線性表的長度,用 n表示(n>=0)。當 n=0時,表示線性表是一個空表,即表中不包含任何資料元素。 線性表中的第一個元素叫做表頭元素,最後一

資料結構演算法及其描述

一、演算法及其描述 1、什麼是演算法 資料元素之間的關係有邏輯關係和物理關係,對應的操作有邏輯結構上的操作功能和具體儲存結構上的操作實現。 把 具體儲存結構上的操作實現方法 稱為演算法。 確切地說,演算法是對特定問題求解步驟的一種描述,它是指令的有限序列,其中每一