高效學習排序演算法

2022-01-21 15:34:27 字數 3879 閱讀 1882

排序是乙個經典的問題,它以一定的順序對乙個陣列或列表中的元素進行重新排序。而排序演算法也是各有千秋,每個都有自身的優點和侷限性。雖然這些演算法平常根本就不用自己去編寫,但作為乙個有追求的程式設計師,還是要了解它們從不同角度解決排序問題的思想。

學習演算法是枯燥的,那怎麼高效的理解它的原理呢?顯然,如果以**的方式,生動形象的把演算法排序的過程展示出來,非常有助於學習。visualgo.net就是乙個視覺化演算法的**,第一次訪問的時候,真的是眼前一亮。本文就對常用的排序進行下總結。

氣泡排序的基本思想就是:把小的元素往前調或者把大的元素往後調。假設陣列有 n 個元素,氣泡排序過程如下:

從當前元素起,向後依次比較每一對相鄰元素(a,b)

如果 a>b 則交換這兩個數

重複步驟1和2,直到比較最後一對元素(第 n-2 和 n-1 元素)

此時最大的元素已位於陣列最後的位置,然後將 n 減 1,並重複步驟1,直到 n=1

氣泡排序的核心**:

public

static

void bubblesort(int a, int

n) }

}}

難點在於邊界的確定,演算法分析:

選擇排序的基本思想就是:每次從未排序的列表中找到最小(大)的元素,放到已排序序列的末尾,直到所有元素排序完畢。假設陣列有 n 個元素且 l=0,選擇排序過程如下:

從 [l...n-1] 範圍中找到最小元素的下標 x

交換第 x 與第 l 位置的元素值

l 加 1,重複以上步驟,直到 l=n-2

選擇排序的核心**:

public

static

void selectionsort(int a, int

n) }

//將最小元素交換到本次迴圈的前端

int tmp =a[minindex];

a[minindex] =a[i];

a[i] =tmp;

}}

演算法分析:

插入排序的基本思想是:每次將待插入的元素,按照大小插入到前面已排序序列的適當位置上。插入排序過程如下:

從第乙個元素開始,該元素可認為已排序

取出下乙個元素,在已排序的元素序列中從後向前掃瞄

如果該元素(已排序)大於待插入元素 ,把它移到下乙個位置

重複步驟 3,直到找到乙個小於或等於待插入元素的位置,將待插入元素插入到下乙個位置

重複步驟 2~5,直到取完陣列元素

插入排序的核心**:

public

static

void insertionsort(int a, int

n) a[j+1] = x; //

插入到下乙個位置 j+1

}}

演算法分析:

希爾排序也稱為增量遞減排序,是對直接插入演算法的改進,基於以下兩點性質:

希爾排序的改進是,使用乙個增量將陣列切分不同的分組,然後在組內進行插入排序,遞減增量,直到增量為 1,好處就是資料能跨多個元素移動,一次比較就可能消除多個元素的交換。基本過程如下:

選取乙個遞增序列,一般使用x/2或者x/3+1

使用序列中最大的增量,對陣列分組,在組內插入排序,遞減增量,直到為 1

核心**:

public

static

void shellsort(int a, int

n) a[j] = x; //

插入 x

}

//遞減增量

h /= 3;

}}

希爾排序陣列拆分插入**,上面的**可以輔助理解,與下圖資料不一致:

演算法分析:

核心**:

public

static

void unrecursivemergesort(int a, int

n)

//歸併兩個有序的子陣列

merge(a, low, mid, high);

}len *= 2; //

增加切分單位

}}

演算法分析:

快排可以說是應用最廣泛的演算法了,它的特點是使用很小的輔助棧原地排序。它也是乙個分而治之的排序演算法,基本思想是:選取乙個關鍵值,將陣列分成兩部分,一部分小於關鍵值,一部分大於關鍵值,然後遞迴的對左右兩部分排序。過程如下:

選取 a[low] 作為關鍵值-切分元素 p

使用兩個指標遍歷陣列(既可一前一後,也可同方向移動),將比 p 小的元素前移,最後交換切分元素

遞迴的對左右部分進行排序

遞迴實現快排核心**:

public

static

void quicksort(int a, int low, int

high)

}public

static

int partition(int a, int low, int

high)

} //交換中樞(切分)元素

int tmp =a[low];

a[low] =a[i];

a[i] =tmp;

return

i;}

演算法分析:

堆排序是利用這種資料結構設計的演算法。堆可看作乙個完全二叉樹,它按層級在陣列中儲存,陣列下標為 k 的節點的父子節點位置分別如下:

堆的表示如下:

堆有序的定義是每個節點都大於等於它的兩個子節點,所以根節點是有序二叉堆中值最大的節點。堆排序就是乙個不斷移除根節點,使用陣列剩餘元素重新構建堆的過程,和選擇排序有點類似(只不過按降序取元素),構建堆有序陣列基本步驟如下:

首先使用 (n-1)/2 之前的元素構建堆,完成後,整個堆最大元素位於陣列的 0 下標位置

把陣列首尾資料交換,此時陣列最大值以找到

把堆的尺寸縮小 1,重複步驟 1 和 2,直到堆的尺寸為 1

核心**:

public

static

void heapsort(int

a) }/**

遞迴的構造大根堆

*/private

static

void sink(int a, int k, int

n) }

演算法分析:

高效鍊錶排序 歸併演算法

排序演算法應該是最基礎的了,快速 歸併 選擇 堆排序等等 對於陣列而言可以隨機訪問,那麼對於鍊錶呢,比如快排,兩個指標分別網後往前走,而沒有前驅指標的單向鍊錶,無法完成這樣的操作,當然了可以採用快慢指標的方式,在提交leetcode的時候,發現快排是會超時的。那麼對於鍊錶而言,可以採取一種怎麼樣的高...

Java實現 高效排序演算法之堆排序

堆排序只需要乙個記錄大小的輔助空間,每個待排序的記錄僅占有乙個儲存空間。在處理堆排序時面臨兩個問題 乙個是如何建堆。另乙個是如何在輸出堆頂後進行調整,成為乙個新堆。建堆的過程主要是通過在n 2 取下限 處開始,反覆進行 篩選 的過程。具體過程見演算法分析及注釋。堆排序的偽 heapsort data...

Java實現 高效排序演算法之基數排序

1 基數排序是一種借助多關鍵字排序的思想對單邏輯關鍵字進行排序的方法。2 演算法的偽 和排序方法如下所示 其中方法是實現對整數的排序方式 基數排序的偽 radixsort for d 1 to 最長數字的最左邊數字所在的位置 根據第d位數字將所有的數字分別分配到堆0至堆9中 將所有證書放進乙個陣列中...