一、什么是排序问题?
输入:n个数的一个序列<a1,a2,……,an>。
输出:输入序列的一个排列<a1',a2',……,an'>,满足a1'≤a2'≤……≤an'。
二、插入排序
插入排序是一种最简单的排序算法,对于少量元素的排序,它也是一种有效的算法。
插入排序的工作方式像许多人(我本人是这样)打扑克牌时抓牌的过程。假如每人手里十三张牌,我们轮流抓牌,第一张拿在手里就是有序的,接着抓第二张牌,这时第一张牌与第二张牌必定产生一个大小关系(包括相等),而我们按照一定的大小关系把第二张牌也拿在手中,这就是插入排序的第二步。继续抓牌,不断重复这个过程,最后手中的十三牌具有一定的大小关系,我们就说排序完成了。
所以插入排序其实就是将未排序的元素插入到已经排好序元素的合适位置上,而我们刚才举的抓牌的例子是最简单的插入排序,也叫直接插入排序。
三、排序过程
我们要排序的数字是{5, 2, 4, 6, 1, 3},且升序排列。
绿色为排序完成,蓝色是目前将要排序,空白是待排序元素。
最开始:
第一次从第二个数字开始比较,发现第二个数字比第一个数字小,那么把第二个数字插入到合适位置:
第二次躺排序完成:
第三趟排序完成:
第四趟排序:
这里将1依次与前面元素比较,发现1应该排在第一位,则把1之前、待插入位置之后的元素依次后移一位,并将1插入:
最后一趟排序:
四、代码
没什么好讲的,用数组来存储元素,逻辑很清晰,当然也可以用数据结构中的顺序表来表示。
数组存储:
#include <iostream>
int main()
{
int arr[6];
for (int i = 0; i < 6; i++)
{
std::cin >> arr[i];
}
for (int i = 1; i < 6; i++)
{
int t = arr[i];//把第一个待排序的元素值保存
int j = i - 1;
while (t < arr[j] && j >= 0)//依次与前面各个元素比较,直至找到合适位置
{
arr[j+1] = arr[j];
j--;
}
arr[j+1] = t;//将待排序元素插入
}
for (int i = 0; i < 6; i++)
{
std::cout << arr[i] << " ";
}
return 0;
}
顺序表存储:
#include <iostream>
typedef struct SqList //定义一个顺序表的结构
{
int arr[6];
int length;
};
void InitSqList(SqList& A) //将顺序表长初始化为0
{
A.length = 0;
}
int main()
{
SqList A;
InitSqList(A);
for (int i = 0; i < 6; i++) //输入元素,并将表长相应增加,此处的6可以键入
{
std::cin >> A.arr[i];
A.length++;
}
for (int i = 1; i < A.length; i++)
{
int t = A.arr[i];
int j = i - 1;
while (t < A.arr[j] && j >= 0)
{
A.arr[j+1] = A.arr[j];
j--;
}
A.arr[j+1] = t;
}
for (int i = 0; i < A.length; i++)
{
std::cout << A.arr[i] << " ";
}
return 0;
}
五、插入排序算法分析
此处不是严格证明,对于最外层循环,从第二个元素到最后一个元素,需要执行的次数即为输入规模n,而每次比较都需要将第一个待排序元素与前面元素比较,这也与输入规模n有关,最好情况是已经有序,不需要跳进while循环,此时时间复杂度为O(n),最坏情况是无序状态,两层循环不能避开,此时时间复杂度为O(n^2),平均时间复杂度也为O(n^2)。