插入排序(insertion sort)
插入排序算法适用于包括向量与列表在内的任何序列结构
插入排序的算法可以简要描述为:始终将序列划分为两个部分: 有序的前缀,无序的后缀;通过迭代,反复的将后缀中的元素移动到前缀中。由此可以看出插入排序算法的不变性:
在任何时刻,相对于当前节点e = S[r], 前缀S[0,r]总是业已有序
算法开始时前缀为空,不变性自然满足。接下来,借助有序序列的查找算法,可在该前缀中定位到不大于e的最大元素。 于是只是需要将e从无序后缀中取出,并紧邻查找返回的位置之后插入,可以使有序前缀的范围扩大至S[0,r]。如此,该前缀范围可不断拓展。当其最终覆盖整个序列时,亦整体有序。
1. 链表的插入排序:
链表的插入删除操作仅需要O(1)时间,但在前缀中搜索插入位置要花费O(n)时间。
/* 列表的选择排序 */
void insertsort(listnode* phead)
{
listnode* curr = phead->next;
listnode* p = NULL;
while (curr != NULL) //遍历整个列表
{
p = curr->next; // 插入操作后列表的结构可能发生改变,要记录后缀开始的位置
insert(phead, curr); // 节点curr插入到前缀中
curr = p; // 更新curr至后缀开始的位置
}
}
/* 节点的插入操作 */
void insert(listnode* phead, listnode* target)
{
listnode* curr = phead->next;
listnode* prev = phead;
listnode* p = NULL;
while (curr != target) // 遍历前缀,寻找插入位置 (prev与curr之间)
{
if (curr->value > target->value)
break;
prev = curr;
curr = curr->next;
}
if (curr == target) // 若不需要交换位置
{
return; // 直接返回
}
p = curr; // 从curr的位置开始
while (p->next != target) // 找到前缀的末尾节点
{
p = p->next;
}
prev->next = target; // 完成 prev 与 target 的连接
p->next = target->next; // 前缀的末尾节点指向后缀的开始节点
target->next = curr; // 完成 target 与 curr 的连接
}
2. 数组的插入排序(int)
void insertsort(int arr[], int n)
{
int insert = 0;