所有的排序都以升序为例。考虑复杂度,考虑稳定性的情况。以及在原基础上步步的优化。
插入排序:
插入排序非常类似于扑克牌排序。
算法:
**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).