分類目錄:《演算法設計與分析》總目錄
排序演算法(二):歸併排序
插入排序對於少量元素的排序是乙個有效的演算法。插入排序的工作方式像許多人排序一手撲克牌。開始時,我們的左手為空並且桌子上的牌面向下。然後,我們每次從桌子上拿走一張牌並將它插入手中正確的位置。為了找到一張牌的正確位置,我們從右到左將它與已在手中的每張牌進行比較,而拿在手上的牌總是排序好的。
對於插入排序,我們將其**過程命名為insertionsort(arr)
,其中的引數是乙個陣列arr
[1,2
,⋯,n
]arr[1, 2, \cdots, n]
arr[1,
2,⋯,
n],包含長度為n
nn的要排序的乙個序列。該演算法原址排序輸入的數:演算法在陣列arr
arrar
r中重排這些數,在任何時候,最多只有其中的常數個數字儲存在陣列外面。在過程insertionsort(arr)
結束時,輸入陣列arr
包含排序好的輸出序列。
def
insertion_sort
(arr)
:for i in
range(1
,len
(arr)):
key = arr[i]
j = i -
1while j >=
0and key < arr[j]
: arr[j +1]
= arr[j]
j -=
1 arr[j +1]
= key
return arr
下圖表明對a=(
5,2,
4,6,
1,3)
a = (5, 2, 4, 6, 1, 3)
a=(5,2
,4,6
,1,3
)該演算法如何工作。下標j
jj指出正被插入到手中的「當前牌」。在for
迴圈(迴圈變數為j
jj)的每次迭代的開始,包含元素a[1
,2,⋯
,j−1
]a[1, 2, \cdots, j - 1]
a[1,2,
⋯,j−
1]的子陣列構成了當前排序好的手中的牌,剩餘的子陣列a[j
+1,j
+2,⋯
,n]a[j + 1, j + 2, \cdots,n]
a[j+1,
j+2,
⋯,n]
對應於仍在桌子上的牌堆。事實上,元素a[1
,2,⋯
,j−1
]a[1, 2, \cdots, j - 1]
a[1,2,
⋯,j−
1]就是原來在位置1
11到j−1
j - 1
j−1的元素,但現在已按序排列.我們把a[1
,2,⋯
,j−1
]a[1, 2, \cdots, j - 1]
a[1,2,
⋯,j−
1]的這些性質形式地表示為乙個迴圈不變式:在第2~8行的for
迴圈的每次迭代開始時,子陣列a[1
,2,⋯
,j−1
]a[1, 2, \cdots, j - 1]
a[1,2,
⋯,j−
1]由原來在a[1
,2,⋯
,j−1
]a[1, 2, \cdots, j - 1]
a[1,2,
⋯,j−
1]中的元素組成,但已按序排列。
迴圈不變式主要用來幫助我們理解演算法的正確性。關於迴圈不變式,我們必須證明三條性質:
當前兩條性質成立時,在迴圈的每次迭代之前迴圈不變式為真。當然,為了證明迴圈不變式在每次迭代之前保持為真,我們完全可以使用不同於迴圈不變式本身的其他已證實的事實。注意,這類似於數學歸納法,其中為了證明某條性質成立,需要證明乙個基本情況和乙個歸納步。這裡,證明第一次迭代之前不變式成立對應於基本情況,證明從一次迭代到下一次迭代不變式成立對應於歸納步。第三條性質也許是最重要的,因為我們將使用迴圈不變式來證明正確性。通常,我們和導致迴圈終止的條件一起使用迴圈不變式。終止性不同於我們通常使用數學歸納法的做法,在歸納法中,歸納步是無限地使用的,這裡當迴圈終止時,停止「歸納」。
讓我們看看對於插入排序,如何證明這些性質成立。
最後,我們用**演示一下插入排序的全過程:
演算法 一 插入排序
插入排序演算法類似於玩撲克時抓牌的過程,玩家每拿到一張牌都要插入到手中已有的牌裡,使之從小到大排好序。撲克牌的插入排序 也許你沒有意識到,但其實你的思考過程是這樣的 現在抓到一張7,把它和手裡的牌從右到左依次比較,7比10小,應該再往左插,7比5大,好,就插這裡。為什麼比較了10和5就可以確定7的位...
排序演算法(一) 插入排序
首先,對排序演算法 輸入 n 個數 輸出 序列的乙個排序,使得a1 a2 an 待排序的數為key 插入排序演算法,是乙個對少量元素進行排序的有效演算法.其偽 如圖 插入排序演算法在形式上類似於我們平時打牌時,邊抽牌邊整理撲克牌的順序,我們將新的牌與手中已經整理好順序的撲克牌進行比較,最終將抽到的牌...
排序演算法(一) 插入排序
一 插入排序 直接插入 二分插入 希爾排序 基本思想 從前面已經排序好的資料中查詢合適的位置,將待排序資料插入到該位置 從後面向前找合適的位置 1 直接插入排序 基本思想 從右向左查詢 從左邊已排序好的資料中查詢合適的位置,插入待排序的資料。private static void derictins...