二分查找和折半插入排序一块说说-很合适~~~
前言
上一篇在聊時間復雜度和空間復雜度時,沒有按指定格式顯示(明明預覽的時候沒問題的),強迫癥的我稍微優化了一下重新發布,目的就是讓小伙伴看著舒服。
上次聊到的直接插入排序在比較有序數據和待插入數據時,是通過依次遍歷的方式進行比較,當數據量比較大時,得考慮進一步優化;折半插入排序就是通過減少有序數據與待插入數據的比較次數,從而提升效率。
正文
1. 先來熟悉一下折半查找
1.1 ?折半查找算法思想
折半查找又稱二分查找,僅適用于有序的順序表;
思想(假設順序表是升序的):
首先將指定值與順序表中中間位置元素進行比較;
若相等,代表找到,則返回該元素的位置;
若不等,需繼續查找;
若指定的值小于順序表中中間元素,則查找前半部分;
若指定的值大于順序表中中間元素,則查找后半部分;
重復以上過程,直到找到元素為止;或者找完所有數據為止,即查找失敗;
1.2 折半查找實現及解析
算法代碼如下(在升序順序表中查數據)
image-20210327174929319執行結果如下:
image-20210327175057909解析查找步驟過程,如下:
圖中分別使用紅、綠、黃箭頭所指的數據分別高、中、低索引位,藍色為需要在順序表中查找的數。
能查到數據的步驟:
image-20210328000114746上圖步驟說明:
第1步將low初始為0,high初始賦值為順序表中的元素個數減1,這里為5;當循環進來時將mid賦值為(low+high)/2,因為mid為int類型,會取整,這里就得到mid為2;然后將索引位為2的數據66與需要查找的數據92進行比較,發現92大于66,需繼續在后半部分查找,所以將low的值改為mid+1,即為3;
第2步進入循環,繼續將mid的賦值為(low+high)/2,因為上一步low的值為3,high的值不變,還是為5,所以得出的mid值為4,然后將索引位為4的數據92與需要查找的數據92進行比較,兩者相等,代表已經找到,返回當時找到的位置mid。
查找失敗時的情況:
image-20210328000247255上圖步驟說明:
第1步將low初始為0,high初始賦值為順序表中的元素個數減1,這里為5;當循環進來時將mid賦值為(low+high)/2,因為mid為int類型,會取整,這里就得到mid為2;然后將索引位為2的數據66與需要查找的數據921進行比較,發現921大于66,需繼續在后半部分查找,所以將low的值改為mid+1,即為3;
第2步進入循環,繼續將mid的賦值為(low+high)/2,因為上一步low的值為3,high的值不變,還是為5,所以得出的mid值為4,然后將索引位為4的數據92與需要查找的數據921進行比較,發現921大于92,需繼續在后半部分查找,所以將low的值改為mid+1,即為5;
第3步進入循環,繼續將mid的賦值為(low+high)/2,因為上一步low的值為5,high的值不變,還是為5,所以得出的mid值為5(這里高、中、低都指向同一位置),然后將索引位為5的數據100與需要查找的數據921進行比較,發現921大于100,需繼續在后半部分查找,所以將low的值改為mid+1,即為6;
第4步進入循環時,low在第3步時變為6,high還是沒變,依然是5,low大于high,不滿足循環條件,代表已經查詢完成,但沒有查詢到數據,跳出循環,返回-1;
1.3 分析折半查找算法性能
時間復雜度
如果傳入的數據規模為n,即有n個元素;第一次在 n/2個元素中查找,第二次在n/(22)個元素中查找,第三次在n/(23)個元素中查找,假如經過x次查找到元素,則得到時間復雜度為O(log2n);
空間復雜度
因為在查找過程中,用到了固定的幾個中間變量(low,mid,high),所以算法過程中消耗的內存是一個常量級別的,則空間復雜度為O(1);
穩定性
由于在算法過程中只是查找,不改變元素的位置,則折半查找算法是穩定的。
綜上所述,插入排序的時間復雜度為O(log2n),空間復雜度為O(1),是穩定算法;
2. 搞明白折半插入排序
2.1 折半插入排序算法思想
折半插入排序是對直接插入排序的優化,直接插入排序在比較過程中依次遍歷有序列表中的元素和待插入數據比較,而折半插入排序是將原來的依次遍歷有序列表換成折半查找算法,提升比較效率,找到合適位置之后,對應的元素需要向后移位,然后將待插入元素插入到騰出的空位即可;重復到排序完成為止。
2.2 折半插入排序算法實現與解析
代碼實現(升序):
image-20210329104257982運行效果如下:
image-20210329104425770步驟解析如圖:
image-20210329123521476步驟說明:
圖中綠線框部分代表是已經排好序的列表,箭頭指的元素是下一個待插入的元素,黃線框部分為剩下的無序元素。黃方塊為每次折半查找到的mid位置,綠方塊表示最后有序列表騰出的位置。
將原始數據array復制到新數組中arrayb中,這步的主要目的是后續不需要聲明額外臨時變量,也為了后續核心代碼實現邏輯簡單易懂,減少過多的判斷;
第1步將第一個元素作為有序列表(第一元素為2),下一個待插入的元素為5,將5放入哨兵位置,即索引為0的位置;然后折半查找,初始low為1,high為第一次也為1;因為剛開始有序列表中只有一個元素,則找到就是2,與哨兵位的值5比較,2小于5,需要繼續在有序列表的后半部分查找,改變low為mid+1,此時為2,大于high,跳出循環;不需要移動位置,保持當前位置不變。
第2步時,有序列表中的元素為2、5,下一個待插入的元素為6,將6放入哨兵位置,即索引為0的位置;然后折半查找:
第2-1步 初始low為1,此時計算出high的值為2;根據low和high計算出mid為1(因為是mid是整數,所以3除以2,取整為1),將mid位的值2與待插入元素6比較,2小于6,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid加1,得到low為2;
第2-1步 上一步得到low為2,high的值仍然為2;根據low和high計算出mid為2,將mid位的值5與待插入元素6比較,5小于6,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid加1,得到low為3;不滿足循環條件,退出折半;不需要移動位置,保持當前位置不變;
第3步時,有序列表中的元素為2、5、6,下一個待插入的元素為1,將1放入哨兵位置,即索引為0的位置;然后折半查找:
第3-1步 初始low為1,此時計算出high的值為3;根據low和high計算出mid為2,將mid位的值5與待插入元素1比較,5大于1,需要繼續在有序列表中的前半部分繼續查找,則改變high的值,為mid減1,得到high為1;
第3-2步 初始low為1,上一步計算出high的值為1;根據low和high計算出mid為1,將mid位的值2與待插入元素1比較,2大于1,需要繼續在有序列表中的前半部分繼續查找,則改變high的值,為mid減1,得到high為0;繼續循環是low大于high,不滿足條件,跳出循環;
第3-3步 根據折半查找比較,得出合適位置為high+1,即需要將待插入元素插入到1位置,需要將2、5、6三個元素依次向后移位,騰出索引位1的位置,將待插入元素1插入到此索引位。
第4步時,有序列表中的元素為1、2、5、6,下一個待插入的元素為9,將9放入哨兵位置,即索引為0的位置;然后折半查找:
第4-1步 初始low為1,此時計算出high的值為4;根據low和high計算出mid為2(因為是mid是整數,所以5除以2,取整為2),將mid位的值2與待插入元素9比較,2小于9,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid+1,得到low為3;
第4-2步 上一步計算出low為3,high的值仍然為4;根據low和high計算出mid為3(因為是mid是整數,所以7除以2,取整為3),將mid位的值5與待插入元素9比較,5小于9,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid+1,得到low為4;
第4-3步 上一步計算出low為4,high的值仍然為4;根據low和high計算出mid為4,將mid位的值6與待插入元素9比較,6小于9,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid+1,得到low為5;繼續循環是low大于high,不滿足條件,跳出循環;
第5步是,有序列表中的元素為1、2、5、6、9,下一個待插入的元素為3,將3放入哨兵位置,即索引為0的位置;然后折半查找:
第5-1步 初始low為1,此時計算出high的值為5;根據low和high計算出mid為3,將mid位的值5與待插入元素3比較,5大于3,需要繼續在有序列表中的前半部分繼續查找,則改變high的值,為mid減1,得到high為2;
第5-2步 初始low為1,上一步計算出high的值為2;根據low和high計算出mid為1(3除以2取整得1),將mid位的值1與待插入元素3比較,1小于3,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid加1,得到low為2;
第5-3步,上一步計算出low為2,第5-1步計算出high為2;根據low和high計算出mid為2,將mid位的值2與待插入元素3比較,2小于3,需要繼續在有序列表中的后半部分繼續查找,則改變low的值,為mid加1,得到low為3;繼續循環,不符合循環條件,循環終止
第5-4步 根據折半查找比較,得出合適位置為high+1,即需要將待插入元素插入到3位置,需要將5、6、9三個元素依次向后移位,騰出索引位3的位置,將待插入元素3插入到此索引位。最終得到排序結果1、2、3 、5 、6 、9;
2.3 折半插入排序算法分析
時間復雜度
在算法過程中有兩層循環,第一層需要遍歷所有元素,則時間復雜度為O(n);第二層循環中包含兩部分算法,第一步是通過折半算法找位置,時間復雜度在剛開始已經分析,為O(log2n);第二步是找到位置之后需要騰出空位,需要將對應元素移位,時間復雜度為O(n);則整體算法的時間復雜度為外層循環的時間復雜度乘以內層循環的時間復雜度,去掉系數和常數,取大的,得出結果為O(n2);
空間復雜度
在算法核心部分只采用了固定的幾個中間變量(i,j,low,mid,high,arrayb[0]),所以算法過程中消耗的內存是一個常量,則空間復雜度為O(1);
穩定性
由于在算法過程中采用折半算法找位置的,使用大于符號進行比較值,所以當遇到相等數據時,位置不會受到改變,則折半插入算法是穩定的。
綜上所述,折半插入排序的時間復雜度為O(n2),空間復雜度為O(1),是穩定算法;
總結
這里說到兩種算法,折半查找(二分查找)算法,折半插入排序算法;最終關于插入排序算法的思想沒變,只是在比較有序列表時做了優化;對于小數據量的排序,感覺不到優化,當數據量大時,比較效率就明顯提升啦;如果不明白的小伙伴調試代碼試試,再不行可以留言,有時間會及時回復。
感謝小伙伴的:點贊、收藏和評論,下期繼續~~~
一個被程序搞丑的帥小伙,關注"Code綜藝圈",跟我一起學~~~
總結
以上是生活随笔為你收集整理的二分查找和折半插入排序一块说说-很合适~~~的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET Core依赖注入初识与思
- 下一篇: BeetleX.Http.Clients