直接插入排序:
很简单,给定序列:23 44 12 13 54 25 41 由小到的排序。对数字所在位置分别编号 1,2,3,4,5,6,7
- 2和1比较,44>23,位置不变 :23 44 12 13 54 25 41
- 3和2比较,12<44,继续3和1比较,12<23,到头了,然后把12插到最前面 :12 23 44 13 54 25 41 于是,1,2两个位置上的数字为有序队列
- 4和3比较,13<44。继续4和2比较,13<23。继续4和1比较,13>12。把13插到12前面 :13 12 23 44 54 25 41 于是,1,2,3三个位置上的数字为有序队列,剩下的为无序队列。
- ········
总之:从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列。
typedef struct {
ReadType r[MAXSIZE]; //一般r[0]闲置用作哨兵单元
int length; //用一个整型变量来记录顺序表的长度
}SqList; //这个表的类型名
//直接插入排序(从小到大排序)
void InsertSort(SqList &L)
{
int j;
for (int i = 2; i <= L.length; i++)
if (L.r[i].key < L.r[i - 1].key) //r[i].key和已经排好的有序部分的最后一个元素的key,也就是和前面的数字中最大的数做比较
{
L.r[0] = L.r[i]; //满足条件(比前面的第一个数字小),放入哨兵单元
L.r[i] = L.r[i - 1]; //先把第[r-1]个后移,覆盖r的位置
for (j = i - 2; L.r[0].key < L.r[j].key; j--) //再把剩下[r-1]前面的&&比r[0]大的全部后移
L.r[j + 1] = L.r[j];
L.r[j + 1] = L.r[0]; //最后的位置用哨兵单元补齐
}//简而言之:if里面做的操作就是 从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列
}
折半插入排序:
和直接插入相比,查找插入位置由顺序查找变为折半查找,不过插入方式还是相同的
void BInsertSort(SqList &L)
{
for (int i = 2; i <= L.length; i++)
{
L.r[0] = L.r[i];
int low = 1; int high = i - 1;
while (low <= high) //用二分法查找在排好的有序的部分中查找找第i个元素插入的位置(找到一个位置m,一个比当前r[i]大和r[i]小的数之间)
{
int m = (low + high) / 2;
if (L.r[0].key < L.r[m].key)
high = m - 1;
else low = m + 1;
}
for (int j = i - 1; j >= high + 1; j--)//找到之后,位置是r[high+1],把r[i](即此时所要插入有序部分的元素) 之前的元素后移,从i-2开始后移
L.r[j + 1] = L.r[j]; //后移即赋值,最后r[high+1]和它后一个元素赋值后相等
L.r[high + 1] = L.r[0]; //最后将要插入的元素r[i]或者r[0](两者相等)插入到二分查找找到的位置r[high+1]
}
}
希尔排序:
直接插入其实是增量为1的一趟直接插入排序 而希尔排序是增量由大变小的好几趟直接插入排序
思路;(简单一点取增量 3,1)
- 分组 把 第1,4,7,10...各元素分成一组 ,把第2,5,8,11...个元素分成一组,依次以3为增量,分完所有元素
- 排序 在以上分好的组中分别进行直接插入排序,使得每一组都有序
- 分组 以增量为1,分组,只能分成一组了
- 排序 在这一组中进行直接插入排序
//待排序记录的存储方式
#define MAXSIZE 50
typedef struct {
int key; //关键字类型默认简化设置为整型
char otherinfo; //其他数据项默认简化设置为char型
}ReadType;
typedef struct {
ReadType r[MAXSIZE]; //一般r[0]闲置用作哨兵单元
int length; //用一个整型变量来记录顺序表的长度
}SqList; //这个表的类型名
//对序列表做一趟增量为dk的希尔插入排序
void ShellInsert(SqList &L, int dk)
{
for (int i = dk + 1; i <= L.length; i++)
if (L.r[i].key < L.r[i - dk].key)
{
L.r[0] = L.r[i];
int j;
//增量为dk组成的一组序列进行直接插入排序
for (j = i - dk; j > 0 && L.r[0].key < L.r[j].key; j -= dk)//把这一组中 已经排好序的有序部分中 大于r[0].key的元素全部后移
L.r[j + dk] = L.r[j];
L.r[j + dk] = L.r[0]; //把r[0]放到有序部分中所有大于r[0].key的元素之后
}
}
//给ShellInsert()不同的增量
void Shellsort(SqList &L, int dt[], int t)
{
for (int k = 0; k < t; k++)
{
ShellInsert(L, dt[k]); // (dt[0] = 5,dt[1] = 3,.....)
}
}
main方法运行:
#include<iostream>
#include <ctime>
using namespace std;
//待排序记录的存储方式
#define MAXSIZE 50
typedef struct {
int key; //关键字类型默认简化设置为整型
char otherinfo; //其他数据项默认简化设置为char型
}ReadType;
typedef struct {
ReadType r[MAXSIZE]; //一般r[0]闲置用作哨兵单元
int length; //用一个整型变量来记录顺序表的长度
}SqList; //这个表的类型名
//插入排序
//产生长度为length的0~100的随机序列
void Make_random(SqList &L, int length)
{
time_t now = time(NULL);
srand(unsigned(now));
L.length = 0;
for (int i = 1; i <= length; i++)
{
L.r[i].key = rand() % 100; //生成0~100的随机数
L.r[i].otherinfo = rand() % 100;
L.length++;
}
}
//公用输出函数
void Cout_SqList(SqList &L)
{
for (int i = 1; i <= L.length; i++)
{
cout << L.r[i].key << " ";
//cout << L.r[i].otherinfo << " ";
}
cout << endl;
}
//直接插入排序(从小到大排序)
void InsertSort(SqList &L)
{
int j;
for (int i = 2; i <= L.length; i++)
if (L.r[i].key < L.r[i - 1].key) //r[i].key和已经排好的有序部分的最后一个元素的key,也就是和前面的数字中最大的数做比较
{
L.r[0] = L.r[i]; //满足条件(比前面的第一个数字小),放入哨兵单元
L.r[i] = L.r[i - 1]; //先把第[r-1]个后移,覆盖r的位置
for (j = i - 2; L.r[0].key < L.r[j].key; j--) //再把剩下[r-1]前面的&&比r[0]大的全部后移
L.r[j + 1] = L.r[j];
L.r[j + 1] = L.r[0]; //最后的位置用哨兵单元补齐
}//简而言之:if里面做的操作就是 从无序队列中选取第一个元素,插入到有序队列中合适的位置,直到无序队列为空。全部为有序队列
}
//折半插入排序:和直接插入相比,查找插入位置由依次查找变为折半查找,插入方式相同
void BInsertSort(SqList &L)
{
for (int i = 2; i <= L.length; i++)
{
L.r[0] = L.r[i];
int low = 1; int high = i - 1;
while (low <= high) //用二分法查找在排好的有序的部分中查找找第i个元素插入的位置(找到一个位置m,一个比当前r[i]大和r[i]小的数之间)
{
int m = (low + high) / 2;
if (L.r[0].key < L.r[m].key)
high = m - 1;
else low = m + 1;
}
for (int j = i - 1; j >= high + 1; j--)//找到之后,位置是r[high+1],把r[i](即此时所要插入有序部分的元素) 之前的元素后移,从i-2开始后移
L.r[j + 1] = L.r[j]; //后移即赋值,最后r[high+1]和它后一个元素赋值后相等
L.r[high + 1] = L.r[0]; //最后将要插入的元素r[i]或者r[0](两者相等)插入到二分查找找到的位置r[high+1]
}
}
//对序列表做一趟增量为dk的希尔插入排序
void ShellInsert(SqList &L, int dk)
{
for (int i = dk + 1; i <= L.length; i++)
if (L.r[i].key < L.r[i - dk].key)
{
L.r[0] = L.r[i];
int j;
//增量为dk组成的一组序列进行直接插入排序
for (j = i - dk; j > 0 && L.r[0].key < L.r[j].key; j -= dk)//把这一组中 已经排好序的有序部分中 大于r[0].key的元素全部后移
L.r[j + dk] = L.r[j];
L.r[j + dk] = L.r[0]; //把r[0]放到有序部分中所有大于r[0].key的元素之后
}
}
//给ShellInsert()不同的增量
void Shellsort(SqList &L, int dt[], int t)
{
for (int k = 0; k < t; k++)
{
ShellInsert(L, dt[k]); // (dt[0] = 5,dt[1] = 3,.....)
}
}
int main()
{
SqList L1;
Make_random(L1, 10);
Cout_SqList(L1);
cout << "直接插入排序:" << endl;
InsertSort(L1);
Cout_SqList(L1);
cout << endl << endl;
SqList L2;
Make_random(L2, 10);
Cout_SqList(L2);
cout << "折半插入排序:" << endl;
BInsertSort(L2);
Cout_SqList(L2);
cout << endl << endl;
SqList L3;
int dt[3] = { 5,3,1 }; //设置增量序列为5,3,1 条件:递减&&最后增量为1
Make_random(L3, 10);
Cout_SqList(L3);
cout << "希尔排序:" << endl;
Shellsort(L3, dt, 3);
Cout_SqList(L3);
cout << endl << endl;
return 0;
}