**问题:**任意给定一组元素序列,利用直接插入排序、折半插入排序和希尔排序对该序列进行排序
分析:
插入排序最好可以类比为打扑克牌时,我们摸完牌后再将牌插到合适得位置。
主要有几个操作:
- 从未排序的序列里摸一张牌,也就是把未排序的第一张牌取出来;
- 和前面牌完序的牌进行大小比较,如果手里的牌比前面的小,就一直交换位置。
直接插入排序
void Insertion_sort(SqList *L)
/*输入待排序的数组和元素个数*/
{
int p,i;
ElementType Tmp;
for (p = 1; p < L->Length; p++) //每次从后面待排序的序列里取出一张往前插,默认A[0]已经排好序
{
Tmp = L->data[p];
for (i = p; i >= 0&&Tmp<L->data[i-1]; i--)
{
L->data[i] = L->data[i - 1];
}
L->data[i] = Tmp;
}
}
折半插入排序
折半插入排序和直接插入排序相比,在确定插入位置的那一步采用折半查找,最后还是逐个移动位置,所以仅减小了关键字的比较次数,儿记录的移动次数没变,时间复杂度O(N2)
void BinInsertion_sort(SqList *L)
/*折半插入算法,插入更快,移动元素并未发生改变*/
{
int p, i, Low, High, Mid;
ElementType Tmp;
for (p = 1; p < L->Length; p++)
{
Tmp = L->data[p];//取出后面一个元素
Low = 0;
High = p-1;
while (Low<=High)
{
Mid = (Low + High) / 2;
if (Tmp < L->data[Mid])
High = Mid - 1;
else
{
Low = Mid + 1;
}
}
for (i = p; i >= Low; i--)
{
L->data[i] = L->data[i - 1];
}
L->data[Low] = Tmp;
}
}
希尔排序
希尔排序,引入一个增量,每次不止消除一个逆序对,任何交换相邻元素的排序算法每交换一次只能消除一个逆序对。要提高效率,我们必须每次不仅消除一个逆序对。因此我们可以将序分成若干个子序列,子序列有相聚一定的距离的元素组成,对每个子序列进行插入排序,这样每次可以消除不止一个逆序对。
void Shell_Sort(SqList *L)
/*希尔排序*/
{
int D;//增量
int p, i;
ElementType Tmp;
for (D = L->Length/2; D>0; D/=2) // 增量每次缩小一半
{
for (p = D; p < L->Length; p++)
{
Tmp = L->data[p];
for (i = p; i >= 0 && L->data[i - D] > Tmp; i--)
{
L->data[i] = L->data[i - D];
}
L->data[i] = Tmp;
}
}
}
完整的实例代码:
// Insertion_sort.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
constexpr auto MaxSize = 100;;
typedef int ElementType;
typedef struct
{
ElementType data[MaxSize];
int Length;
}SqList;
void Swap(ElementType *a, ElementType *b)
/*交换a,b*/
{
ElementType tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void Insertion_sort(SqList *L)
/*输入待排序的数组和元素个数*/
{
int p,i;
ElementType Tmp;
for (p = 1; p < L->Length; p++) //每次从后面待排序的序列里取出一张往前插,默认A[0]已经排好序
{
Tmp = L->data[p];
for (i = p; i >= 0&&Tmp<L->data[i-1]; i--)
{
L->data[i] = L->data[i - 1];
}
L->data[i] = Tmp;
}
}
void BinInsertion_sort(SqList *L)
/*折半插入算法,插入更快,移动元素并未发生改变*/
{
int p, i, Low, High, Mid;
ElementType Tmp;
for (p = 1; p < L->Length; p++)
{
Tmp = L->data[p];//取出后面一个元素
Low = 0;
High = p-1;
while (Low<=High)
{
Mid = (Low + High) / 2;
if (Tmp < L->data[Mid])
High = Mid - 1;
else
{
Low = Mid + 1;
}
}
for (i = p; i >= Low; i--)
{
L->data[i] = L->data[i - 1];
}
L->data[Low] = Tmp;
}
}
void Shell_Sort(SqList *L)
/*希尔排序,引入一个增量,每次不止消除一个逆序对,任何交换相邻元素的排序算法每交换一次只能消除一个逆序对。
要提高效率,我们必须每次不仅消除一个逆序对。因此我们可以将序分成若干个子序列,子序列有相聚一定的距离的元素组成
,对每个子序列进行插入排序,这样每次可以消除不止一个逆序对。
*/
{
int D;//增量
int p, i;
ElementType Tmp;
for (D = L->Length/2; D>0; D/=2) // 增量每次缩小一半
{
for (p = D; p < L->Length; p++)
{
Tmp = L->data[p];
for (i = p; i >= 0 && L->data[i - D] > Tmp; i--)
{
L->data[i] = L->data[i - D];
}
L->data[i] = Tmp;
}
}
}
void DisPlay(SqList L)
{
int i;
for (i = 0; i < L.Length; i++)
{
printf("%-5d",L.data[i]);
}
printf("\n");
}
int main()
{
int A[] = { 2,5,1,3,5,7,11 };
int i,len;
len = sizeof(A) / sizeof(A[0]);
SqList L,L1,L2;
for (size_t i = 0; i < len; i++)
{
L.data[i] = A[i];
}
L.Length = len;
L1 = L2 = L;
printf("排序前:");
DisPlay( L);
printf("插入排序:");
Insertion_sort(&L);
DisPlay(L);
printf("折半插入排序:");
BinInsertion_sort(&L1);
DisPlay(L1);
printf("希尔排序:");
Shell_Sort(&L2);
DisPlay(L2);
}
程序运行结果: