資料結構圖文解析之:直接插入排序及其優化(二分插入排序)解析及C++實現
0. 資料結構圖文解析系列
1. 插入排序簡介
插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上通常採用就地排序,因而空間複雜度為O(1)。在從後向前掃描的過程中,需要反覆把已排序元素逐步向後移動,為新元素提供插入空間,因此插入排序的時間複雜度為O(n^2);
2. 直接插入排序圖解
一般來說,插入排序都採用在陣列上就地排序實現。具體演算法描述如下:
- 從第一個元素開始,該元素可以認為已經被排序
- 取出下一個元素,在已經排序的元素序列中從後向前掃描
- 如果該元素(已排序)大於新元素,將該元素移到下一位置
- 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置
- 將新元素插入到該位置後
- 重複步驟2~5
假設我們要對陣列{12,4,5,2,6,14}進行插入排序,排序過程為:
2.1. 程式碼實現
template <typename T> void InsertSort(T array[],int length) { if (array == nullptr || length < 0) return; int i, j; for (i = 1; i < length; i++) { if (array[i]<array[i - 1]) { int temp = array[i]; for (j = i - 1; array[j]>temp; j--) //元素後移 { array[j + 1] = array[j]; } array[j+1] = temp; //在合適的位置上出入元素 } } }
2.2. 複雜度分析
- 插入排序的最好情況是陣列已經有序,此時只需要進行n-1次比較,時間複雜度為O(n);
- 最壞情況是陣列逆序排序,此時需要進行n(n-1)/2次比較以及n-1次賦值操作(插入);
- 平均來說插入排序演算法的複雜度為O(n^2)。
插入排序不適合對大量資料進行排序應用,但排序數量級小於千時插入排序的效率還不錯,可以考慮使用。插入排序在STL的sort演算法和stdlib的qsort演算法中,都將插入排序作為快速排序的補充,用於少量元素的排序(通常為8個或以下)。
直接插入排序採用就地排序,空間複雜度為O(1).
2.3. 穩定性
直接插入排序是穩定的,不會改變相同元素的相對順序。
3. 二分查詢插入排序
上面的插入排序實現中,為了找到元素的合適的插入位置,我們採用從後到前遍歷的順序查詢進行比較,為了減少比較的次數,我們可以換種查詢策略:採用二分查詢。
我們定義一個二分查詢函式,函式返回插入位置的下標:
/*二分查詢函式,返回插入下標*/
template <typename T>
int BinarySearch(T array[], int start, int end, T k)
{
while (start <= end)
{
int middle = (start + end) / 2;
int middleData = array[middle];
if (middleData > k)
{
end = middle - 1;
}
else
start = middle + 1;
}
return start;
}
//二叉查詢插入排序
template <typename T>
void InsertSort(T array[], int length)
{
if (array == nullptr || length < 0)
return;
int i, j;
for (i = 1; i < length; i++)
{
if (array[i]<array[i - 1])
{
int temp = array[i];
int insertIndex = BinarySearch(array, 0,i, array[i]);//使用二分查詢在有序序列中進行查詢,獲取插入下標
for (j = i - 1; j>=insertIndex; j--) //移動元素
{
array[j + 1] = array[j];
}
array[insertIndex] = temp; //插入元素
}
}
}
3.2. 複雜度分析
我們這個二分查詢的演算法並不會因為等於某一個值而停止查詢,它將查詢整個序列直到start<=end條件不滿足而得到插入的位置,所以對於長度為n的陣列來說,比較次數為log2n ,時間複雜度為O(log2n)。二分插入排序的主要操作為比較+後移賦值,則:
- 最壞情況:每次都在有序序列的起始位置插入,則整個有序序列的元素需要後移,時間複雜度為O(n^2)
- 最好情況:待排序陣列本身就是正序的,每個元素所在位置即為它的插入位置,此時時間複雜度僅為比較時的時間複雜度,為O(log2n)
- 平均情況:O(n^2)
空間複雜度上, 二分插入排序也是就地排序演算法,它的空間複雜度為O(1).
3.3. 穩定性
二分插入排序是穩定的。元素的相對順序在排序後不會被改變。
相關推薦
資料結構圖文解析之:直接插入排序及其優化(二分插入排序)解析及C++實現
0. 資料結構圖文解析系列 1. 插入排序簡介 插入排序是一種簡單直觀的排序演算法,它也是基於比較的排序演算法。它的工作原理是通過不斷擴張有序序列的範圍,對於未排序的資料,在已排序中從後向前掃描,找到相應的位置並插入。插入排序在實現上通常採用就地排序,因而空間複雜度為O(1)。在從後向前掃描的過程中,需要反
資料結構圖文解析之:哈夫曼樹與哈夫曼編碼詳解及C++模板實現
0. 資料結構圖文解析系列 1. 哈夫曼編碼簡介 哈夫曼編碼(Huffman Coding)是一種編碼方式,也稱為“赫夫曼編碼”,是David A. Huffman1952年發明的一種構建極小多餘編碼的方法。 在計算機資料處理中,霍夫曼編碼使用變長編碼表對源符號進行編碼,出現頻率較高的源符號採用較短的編碼,
mooc浙大資料結構PTA習題之最大子列和問題2(線上處理)
01-複雜度2 Maximum Subsequence Sum(25 分) Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to
白話空間統計之:Moran's I(莫蘭指數)
元素 cal ltr div sdn glob 之間 計算 fonts 前兩天聊了空間統計學裏面的兩個經典概念,今天來說說第一篇文章留下的大坑:Moran‘s I。 首先,Moran‘s I這個東西。官方叫做:莫蘭指數,是澳大利亞統計學家帕特裏克·阿爾弗雷德·
【資料結構】二叉樹的建立和遍歷(非遞迴)
該程式使用的是遞迴地建立方法,以及非遞迴的遍歷演算法 執行環境:Dev-C++ #include <stdio.h> #include <stdlib.h> typedef struct node{ char data; struct node *lchild
ZeroMQ介面函式之 :zmq_inproc – ØMQ 本地程序內(執行緒間)傳輸方式
————————————————————————————————————— zmq_inproc(7) ØMQ Manual - ØMQ/4.2.0 Name zmq_inproc – ØMQ 本地程序內(執行緒間)傳輸方式 Synopsis 程序內傳輸方式意味著在共享ZMQ con
【資料結構與演算法】Huffman樹&&Huffman編碼(附完整原始碼)
出處:http://blog.csdn.net/ns_code/article/details/19174553 Huffman Tree簡介 赫夫曼樹(Huffman Tree),又稱最優二叉樹,是一類帶權路徑長度最短的樹。假設有n個權值{w1,
資料結構與算法系列----多源最短路徑(Floyd-Warshall演算法)
任意兩點最短路徑被稱為多源最短路徑,即給定任意兩個點,一個出發點,一個到達點,求這兩個點的之間的最短路徑,就是任意兩點最短路徑問題,多源最短路徑,而Floyd-Warshall演算法最簡單,只有5行程式碼,即可解決這個問題。 上圖中有4個城市8條公路,公路上的數字表示這條
【資料結構】高效雙向連結串列list、樹tree(二叉樹)
vi正常模式下: "shift + g" 跳到最後一行 "gg" 跳到第一行 <效率更高的雙向連結串列結構程式碼>/*程式碼*/ 01link.c #include <stdlib.h> #include "01link.h" //連結串列初始化 v
BZOJ - 5427:最長上升子序列 (二分&思維)
現在給你一個長度為n的整數序列,其中有一些數已經模糊不清了,現在請你任意確定這些整數的值, 使得最長上升子序列最長。(為何最長呢?因為hxy向來對自己的rp很有信心) Input 第一行一個正整數n 接下來n行第i行格式如下
插入排序演算法+優化 (二分查詢優化有序部分)C語言實現
直接插入排序 插入排序思想 直接插入排序思想是將待排序的陣列看作兩個部分:有序部分和無序部分,排序過程就是不斷將無序部分的元素插入到有序部分合適的位置上,使有序部分元素不斷增加而無序部分資料不斷減少,直到陣列全部有序為止。 假設陣列A[0...
動態規劃:最長上升子序列(二分演算法 nlogn)
解題心得: 1、在資料量比較大的時候n^2會明顯超時,所以可以使用nlogn 的演算法,此演算法少了雙重迴圈,用的lower_bound(二分法)。 2、lis中的數字並沒有意義,僅僅是找到最小點lis[0]和最大點lis[len],其中,在大於lis[le
資料結構圖文解析之:樹的簡介及二叉排序樹C++模板實現.
閱讀目錄 0. 資料結構圖文解析系列 1. 樹的簡介 1.1 樹的特徵 1.2 樹的相關概念 2. 二叉樹簡介 2.1 二叉樹的定義 2.2 斜樹、滿二叉樹、完全二叉樹、二叉查詢樹 2
資料結構圖文解析之:佇列詳解與C++模板實現
正文 回到頂部 0. 資料結構圖文解析系列 回到頂部 1. 佇列簡介 回到頂部 1.1 佇列的特點 佇列(Queue)與棧一樣,是一種線性儲存結構,它具有如下特點: 佇列中的資料元素遵循“先進先出”(First In First Out)的原則,簡稱FI
資料結構圖文解析之:二叉堆詳解及C++模板實現
0. 資料結構圖文解析系列 1. 二叉堆的定義 二叉堆是一種特殊的堆,二叉堆是完全二叉樹或近似完全二叉樹。二叉堆滿足堆特性:父節點的鍵值總是保持固定的序關係於任何一個子節點的鍵值,且每個節點的左子樹和右子樹都是一個二叉堆。 當父節點的鍵值總是大於或等於任何一個子節點的鍵值時為最大堆。 當父節點的鍵值總是小於
資料結構圖文解析之:陣列、單鏈表、雙鏈表介紹及C++模板實現
0. 資料結構圖文解析系列 1. 線性表簡介 線性表是一種線性結構,它是由零個或多個數據元素構成的有限序列。線性表的特徵是在一個序列中,除了頭尾元素,每個元素都有且只有一個直接前驅,有且只有一個直接後繼,而序列頭元素沒有直接前驅,序列尾元素沒有直接後繼。 資料結構中常見的線性結構有陣列、單鏈表、雙鏈表、迴圈
資料結構圖文解析之:棧的簡介及C++模板實現
0. 資料結構圖文解析系列 1. 棧的簡介 1.1棧的特點 棧(Stack)是一種線性儲存結構,它具有如下特點: 棧中的資料元素遵守”先進後出"(First In Last Out)的原則,簡稱FILO結構。 限定只能在棧頂進行插入和刪除操作。 1.2棧的相關概念 棧的相關概念: 棧頂與棧底:允許元素
資料結構圖文解析之:二分查詢及與其相關的幾個問題解析
0. 資料結構圖文解析系列 1. 二分查詢簡介 二分查詢大家都不陌生,可以說除了最簡單的順序查詢之外,我們第二個接觸的查詢演算法就是二分查找了。順序查詢的時間複雜度是O(n),二分查詢的時間複雜度為O(logn)。在面試中二分查詢被考察的概率還是比較高的,上次去面試時就遇到手寫二分查詢的題目。二分查詢不難,
資料結構與演算法之直接插入排序
一、前言直接插入排序(Insertion Sort)序是一種最簡單的插入排序。為簡化問題,在此我們只討論升序排序。二、演算法思想插入排序:每一趟將一個待排序的記錄,按照其關鍵字的大小插入到有序佇列的合適位置裡,直到全部插入完成。假設有一組無序序列 R0, R1, ... ,
資料結構實驗之棧與佇列五:下一較大值(一,二)
資料結構實驗之棧與佇列五:下一較大值(一,二) Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 對於包含n(1<=n<=1000)個整數的序列,對於序