所有的排序都以升序爲例。考慮複雜度,考慮穩定性的情況。以及在原基礎上步步的優化。
插入排序:
插入排序非常類似於撲克牌排序。
算法:
**1.在執行過程中,插入排序會把序列分爲2部分。其中頭部是已經排好序的,尾部是待排序的。
**2.從頭開始掃描每一個元素。每當掃描到一個元素,就把它插入到頭部合適的位置,使得頭部數據依然保持有序。
圖片實例:
插入排序:
算法:待排序的序列與已經排序好的序列比較進行比較,如果待排序序列比已經排好序的序列小,就交換位置。
void InsertionSort::sort(int array[], int len)
{
if (array == NULL|| len < 2)
{
return;
}
this->m_array = array;
this->m_len = len;
for (int begin = 1; begin < this->m_len; begin++)
{
//默認:第一個元素是有序的
int cur = begin;
while (cur > 0 && cmp(cur, cur - 1) < 0)
{
this->swap(cur, cur - 1);
cur--;
}
}
for (int i = 0; i < this->m_len; i++)
{
cout << this->m_array[i] << "_";
}
}
逆序對(inversion)
什麼是逆序對?
比如數組[2,3,8,6,1]的逆序對是[2,1], [3,1],[8,1],[8,6],[6,1]共5個逆序對。
插入排序的時間複雜度與逆序對的數量成正比關係。
插入排序優化1:
思路:將交換轉爲挪動。(省去不停的交換過程)
**1.先將待交換的元素備份
**2.頭部有序的數據頭部有序的數據中比待插入元素大的,都朝着尾部方向挪動一個位置。
**3.將待插入的元素放在合適的位置
void InsertionSort1::sort(int array[], int len)
{
if (array == NULL || len < 2)
{
return;
}
this->m_array = array;
this->m_len = len;
for (int begin = 1; begin < this->m_len; begin++)
{
int cur = begin;
//備份待排序元素
int v = this->m_array[cur];
while (cur > 0 && this->cmpElements(v, array[cur -1]) < 0)
{
//挪動數組元素
this->m_array[cur] = this->m_array[cur - 1];
cur--;
}
this->m_array[cur] = v;
}
for (int i = 0; i < this->m_len; i++)
{
cout << this->m_array[i] << "_";
}
}
插入排序 - 二分搜索優化3
1.在元素v的插入過程中,可以使用二分搜索出合適的插入位置,然後再將元素V插入。
二分搜索:
舉例:
插入排序:
void InsertionSort2::sort(int array[], int len)
{
if (array == NULL || len < 2)
{
return;
}
this->m_array = array;
this->m_len = len;
for (int begin = 1; begin < this->m_len; begin++)
{
int v = this->m_array[begin];
int insertIndex = search(begin);
//將[insertIndex,begin)範圍內的元素往右挪動一個單位
//挪動方法一:
for (int i = begin; i > insertIndex; i--)
{
this->m_array[i] = this->m_array[i - 1];
}
//挪動方法二:
/*for (int i = begin - 1; i >= insertIndex; i--)
{
this->m_array[i + 1] = this->m_array[i];
}*/
this->m_array[insertIndex] = v;
}
for (int i = 0; i < this->m_len; i++)
{
cout << this->m_array[i] << "_";
}
}
根據二分搜索找到合適的插入的位置:
//利用二分搜索找到 index 位置元素的待插入位置
//index中所包含的信息有:已經排好序的元素個數。[0,index);
int InsertionSort2::search(int index)
{
int v = this->m_array[index];
int begin = 0;
int end = index;
while (begin < end)
{
int mid = (begin + end) >> 1;
if (this->cmpElements(v,this->m_array[mid]) < 0)
{
end = mid;
}
else
{
begin = mid + 1;
}
}
return begin;
}
總結:使用二叉搜索後,只是減少了比較的次數,但插入排序的平均時間複雜度依然是O(n^2).