插入排序非常類似於撲克牌的排序
執行流程:
1 在執行過程中,插入排序會將序列分為兩部分:頭部是已經排好序的,尾部是待排序的。
2 從頭開始掃瞄每乙個元素
每當掃瞄到乙個元素,就將它插入到頭部合適的位置,使得頭部陣列仍然保持有序。
不難寫出**:
public
class
sort
;insertsort
(array);}
/**插入排序*/
public
static
void
insertsort
(int
array)
else}}
for(
int i =
0; i < array.length; i++)}
}
外面的迴圈,prepareinsert指的是準備插入的資料索引
裡面的迴圈,是已經排序好的部分
mj大神是這樣寫的:
/**插入排序2*/
public
static
void
insertsort2
(int
array)
for(
int i =
0; i < array.length; i++
)}
其實是跟上面的寫法一樣的,只是for迴圈變為了while迴圈。
什麼是逆序對?
陣列[2, 3, 8 ,6, 1]的逆序對為:
<2, 1> < 3, 1> <8, 1> <6, 1> <8, 6>一共5個逆序對
插入排序的時間複雜度與逆序對的數量成正比關係
逆序對的數量越多,插入排序的時間複雜度越高
最壞、平均時間複雜度:o(n^2)
最好時間複雜度:o(n)
空間複雜度:o(1)
屬於穩定排序
當逆序對的數量極少時,插入排序的效率特別高
甚至速度比o(nlogn)級別的快速排序還要快
資料量不是特別大的時候,插入排序的效率也是非常好的。
優化方案一:
將交換轉為挪動
首先,我們觀察到,上面的**是每次都要比較大小,就跟氣泡排序一樣,兩兩比較。
有一種優化方案,將待插入的元素備份,然後比較大小,比較大小:
前大後小,將前面元素往後移動,直接覆蓋後乙個元素,繼續將前前元素與備份元素做比較,以此類推。直至找到合適的位置(前小後大),將備份元素插入到合適位置。
前小後大,不動,結束迴圈。
這種雖然還是要乙個乙個移動,但是,少了過程中的交換,直接將找到位置做一次交換即可。
官方點的語言:
1 先將待插入的元素備份
2 頭部有序資料中比待插入元素大的,都朝尾部方向挪動乙個位置
3 將待插入元素放到最終的合適位置
不難寫出優化**:
/**插入排序*/
public
static
void
insertsort
(int
array)
else
//如果走到了這,說明沒有找到合適的插入位置,也就是,所有的元素都是大於要插入的元素的。
//那麼,需要將待插入的元素插入到最前面
if(middle ==1)}}}
當然,也可以使用while迴圈
/**插入排序*/
public
static
void
insertsort2
(int
array)
array[current]
= beginvalue;
}}
好像,使用for、while寫的**更簡便些。
對於如何找出合適的位置,由於前面一部分已經是有序排序,對於有序排序,有一種方法查詢元素效率比乙個乙個比較的查詢效率要高,這就是二分搜尋
二分搜尋又稱為二分查詢
如何確定乙個元素在陣列中的位置?(假設陣列裡面全都是整數)
如果是無序的陣列,從第0個位置開始遍歷搜尋,平均時間複雜度為o(n)
如果是有序的陣列,使用二分搜尋,最壞的時間複雜度為o(logn)
每次去除一半,相當於乙個二叉樹,很容易得出是高度最大是logn
二分搜尋思路
假設在[begin, end)範圍內搜尋某個元素v,mid == (begin + end)/2
或者mid == begin + (end - begin)/2
m = array[mid];
如果 vm,去[mid + 1, end)範圍內二分搜尋
如果 v=m,直接返回mid,就是要搜尋的值所在位置
不難寫出二分查詢的**:
/**二分查詢,並返回index*/
public
static
intbinarysearch
(int
array,
int value)
else
if(value < middlevalue)
else
}return-1
;}
當然,你也可以使用遞迴來寫:
public
static
intbinarysearch2
(int
array,
int value,
int begin,
int end)
else
if(value < middlevalue)
else
}return-1
;}
有乙個問題需要注意的是,如果在陣列裡面有相同元素,二分查詢找到的下標是不確定的。
比如[1, 1, 1, 1, 1, 1]
優化方案二:
利用二分查詢,找出待插入的位置,然後將提前備份的元素插入合適的位置。
比如:
index 0 1 2 3 4 5 6 7
value 2 4 8 8 8 12 14 0
如果value = 5, 則插入位置為2
如果vaue = 1, 則插入位置為0
如果value = 15, 則插入位置為7
如果vaue = 8, 則插入位置為5
要求二分搜尋返回的插入位置:第乙個大於value的元素位置
明顯,前面兩種的二分查詢並不能滿足我們的要求,我們需要對二分查詢進行改造。
public
class
test
;insertsort
(array)
;for
(int i =
0; i < array.length; i++)}
public
static
void
insertsort
(int
array)
//將待插入值放在待插入位置
array[insertindex]
= beginvalue;}}
/**輸入乙個index,尋找index的值需要插入的位置index*/
public
static
intbinarysearch
(int
array,
int index)
else
}return begin;
}}
需要注意的是,使用了二分搜尋後,只是減少了比較次數,但插入排序的平均時間複雜度依然是o(n^2)。
return end;也可以,因為,while(begin < end){},能走到後面,則begin >= end
資料結構與演算法 插入排序
將乙個資料插入到已經排好序的有序資料中,從而得到乙個新的 個數加一的有序資料 插入排序分為兩種 直接插入排序和希爾排序 插入排序與打撲克時整理手上的牌非常類似。摸來的第1張牌無須整理,此後每次從桌上的牌 無序區 中摸最上面的1張並插入左手的牌 有序區 中正確的位置上。為了找到這個正確的位置,須自左向...
演算法與資料結構 插入排序
例如 給定乙個無序陣列int arr n代表集合陣列的長度,給出乙個演算法將陣列arr按照從小到大的順序進行排列。插入排序 看當前位置i的值是否比它前乙個數小,如果小就與前面的數交換位置。public static void insertionsort int arr,int n public st...
資料結構與演算法 插入排序
一 排序的相關概念 1 排序 將任意序列的資料元素,重新排列成按關鍵字有序 遞增有序或遞減有序 的序列過程。2 穩定性 若在排序過程中,序列的兩個關鍵字值相同的記錄,在排序結束後,相對位置不發生改變,則稱所用的排序方法為穩定的。3 排序方法的兩個效能指標 時間複雜度和空間複雜度。二 插入排序 1 基...