本文讲述几大经典排序算法之一–插入排序的基本原理,详细步骤,C++完整代码实现,复杂度分析。
1. 插入排序基本原理:
将一个序列分为两部分: 已排好序的和未排序的。将为排好序的序列里的元素一次插入已排序序列的合适位置,直到未排序序列为空。
向已排序的序列中插入元素 newEle 的步骤简述如下
从右到左将已排好序的序列中的元素与待插元素比较,将已排好序的序列中大于newEle的元素依次往后移动一个位置,直到遇到不大于newEle的元素,即找到了合适的位置,最后插入待排元素。
1.1. 伪代码: (参照算法导论)
1.2. 举例子一步一步描述:
初始序列 A : A[8] = {6 8 5 9 4 3 7}
2. C++代码:
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int>::size_type sizeType;
void insertSort(vector<int> &vec)
{
int vecSize = vec.size();
int j;
for (int i = 1; i < vecSize; i++) // i 表示已经排好序的子数组大小减一
{
int insertValue = vec[i]; // 将这个值插入已经排好序的数组
for (j = i - 1; j >= 0; j--)
{
if (insertValue >= vec[j])
break; // 找到了要插入 insertValue 的位置 j
vec[j + 1] = vec[j];
}
vec[j + 1] = insertValue;
}
}
void init(vector<int> & vec)
{
int eleValue;
cout << "input the element values: " << endl;
while (cin >> eleValue)
{
vec.push_back(eleValue);
}
cin.clear();
}
void print(vector<int>& vec)
{
for (sizeType index = 0; index < vec.size(); index++)
{
cout << vec[index] << " ";
}
cout << endl;
}
int main()
{
vector<int> vec;
init(vec);
cout << "Before sorted : " << endl;
print(vec);
insertSort(vec);
cout << "After Sorted :" << endl;
print(vec);
return 0;
}
简单例子测试:
复杂用力测试,并计算排序操作时间
start = clock();
insertSort(origArr1);
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "随机生成的序列用时:" << duration << "sec" << endl;
分别输入长度都为 256 的三种已排程度不同的序列,其中
序列1: 随机产生一定大小范围内的数据
序列2: 前100个数已经排好序,后 156个数随机产生
序列3: 完全逆序,即 从大到小依次排列的一组数
运行时间如下
3. 算法复杂度分析
根据插入排序的原理可知,消耗运行时间主要由执行的操作步数(这里包括比较元素大小,转移已排序列中的元素,插入新元素)决定,操作步数独立于机器。
case1: 最坏情况,即初始序列已逆序排序。
case2: 最好情况,即初始序列已顺序排序。
根据伪代码求每个操作的执行次数:
case1:
step1: n
step2: n-1
step3: n-1
step4: 1 + 2 + ··· + (n-1) = n ( n-1 )/2*
step5: 1 + 2 + ··· + (n-1) = n(n-1 )/2*
step6: 1 + 2 + ··· + (n-1) = n(n-1 )/2*
step7: n-1
忽略 n 的低次项,最坏情况的时间复杂度是为n 的二次函数,表示为 O(n^2)
case2:
step1: n
step2: n-1
step3: n-1
step4: 1
step5: 0
step6: 0
step7: n-1
即每次将待插入元素比较都有 A[index] <= A[index - 1],即不用移动已排好的序列元素,直接将待插入的元素放到原先的位置即可。操作次数与元素个数 n 成线性关系,即时间复杂度为 O(n)
总体分析:插入排序比较适合已经有部分元素排好序,这样可以减少元素移动的次数。
另外,插入排序一下几个优点
1. 需要增加一个额外的空间存储等待插入的一个元素(newEle),除此之外序列的其他元素都在原有的存储空间内移动,不需要再增加其他额外的空间。
2. 如果有两个元素数值相等,即在比较时 newEle <= A[j], 不会移动 A[j]。 因此,经过排序后,保持了它们的相对位置。即插入排序是稳定的排序方法。
本菜鸟处于初步学习算法阶段,将所学的知识进行总结整理,希望广大网友不吝赐教,提出宝贵的意见,共同探讨,小的将不甚感激。