資料結構與演算法 排序 插入排序 二分搜尋

2021-10-09 21:29:36 字數 4142 閱讀 7320

插入排序非常類似於撲克牌的排序

執行流程:

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 基...