1. 直接插入,升序
将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
直接插入头文件
#pragma once
#define MAXSIZE 20
#define T int
typedef T Seqlist[MAXSIZE];
void swap(T *a,T *b)
{
T temp = *a;
*a = *b;
*b = temp;
}
void Insert(Seqlist &L,int n) //
{
for(int i = 1;i<n;++i)
{
if(L[i] < L[i-1])// 若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入
{
swap(&L[i],&L[i-1]);
for(int j = i-1;j>0&&L[j]<L[j-1];--j)
{
swap(&L[j],&L[j-1]);
}
}
}
}
直接插入测试文件
#include<iostream>
#include"sort.h"
using namespace std;
void main()
{
Seqlist L = {16,25,8,25,21,49,3,5};
int n = 8;
Insert(L,n);
for(int i = 0;i < 8;++i)
{
cout<<L[i]<<" ";
}
}
2.(折半插入)二分法插入算法
比较直接插入,减少了关键值的比较,但数据移动次数不变
#define MAXSIZE 20
#define T int
typedef T Seqlist[MAXSIZE];
void Binary_insert(Seqlist &L,int n) //
{
for(int i = 2;i <n;++i)
{
L[0] = L[i]; //具备临时空间功能
int low = 1;
int high = i-1;
while(low <= high)
{
int mid = (low + high)/2;
if(L[0] >= L[mid])
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
for(int k = i;k > high+1;--k)
{
L[k] = L[k-1];
}
L[high+1] = L[0];
}
}
二分法插入算法的测试
void main()
{
Seqlist L = {0,16,25,8,25,21,3,49,5};
int n = 9;
//Insert(L,n);
Binary_insert(L,9);
for(int i = 1;i < 9;++i) //注意:此时L[0]储存的是临时对象的值
{
cout<<L[i]<<" ";
}
}
3. 2路插入排序
需借助一个与数据相同大小的内存空间,在折半插入排序算法上,减少其数据移动次数
#define MAXSIZE 20
#define T int
typedef T Seqlist[MAXSIZE];
void Two_ways_insert(Seqlist &L,int n)
{
int i,j;
Seqlist sq;//需借助一个大小与原数据相同大小的内存空间
sq[0] = L[0];
int head,tail;
head = tail = 0;
for(i = 1;i < n;++i)
{
if(L[i] < sq[head])
{
head = (head - 1 + n)%n;//循环赋值,模是关键
sq[head] = L[i];
}
else if(L[i] > sq[tail])
{
tail++;
sq[tail] = L[i];
}
else
{
tail++;
sq[tail] = sq[tail-1];
for(j = tail-1;L[i]<sq[(j-1+n)%n];j=(j-1+n)%n)
{
sq[j] = sq[(j-1+n)%n];
}
sq[j] = L[i];
}
}
for(i = 0;i < n;++i)
{
L[i] = sq[head];
head = (head + 1)%n;
}
}
2路插入排序测试文件
void main()
{
Seqlist L = {16,25,8,25,21,3,49,5};
int n = 8;
//Insert(L,n);
Two_ways_insert(L,8);
for(int i = 0;i < 8;++i)
{
cout<<L[i]<<" ";
}
}
4. 表插入排序
采用静态链表作为底层存储结构,达到不移动数据只改变指针来完成,求得一个有序链表节点,不能直接查找
#define MAXSIZE 20 //默认定义数据大小为20
#define T int
typedef T Seqlist[MAXSIZE];
#define MAXVALUE 0x7fffffff
typedef struct SLNode
{
T data;
int link;
}SLNode;
typedef SLNode Table[MAXSIZE];
void Table_insert_sort(Table &t,int n)
{
t[0].link = 1;
int p,q;//q为p的前驱
for(int i = 2;i<n;++i)
{
p = t[0].link;
q = 0;
while(p != 0 && t[p].data <= t[i].data)
{
q = p;
p = t[p].link;
}
t[i].link = t[q].link;
t[q].link = i;
}
}
表插入测试
void main()
{
Seqlist L = {0,16,25,8,25,21,3,49,5};
//Seqlist L = {0,49,38,65,97,76,13,27,49};
int i,n = 9;
Table tb;
tb[0].data = MAXVALUE;
tb[0].link = 0;
for(i = 0;i<n;++i)
{
tb[i].data = L[i];
tb[i].link = 0;
}
Table_insert_sort(tb,n);
for(i = 0;i<n;++i)
{
cout<<tb[i].data<<" ";
}
cout<<endl<<endl;
for(i = 0;i<n;++i)
{
cout<<tb[i].link<<" ";
}
cout<<endl<<endl;
for(i = 0;i<n;++i)
{
cout<<i<<" ";
}
cout<<endl<<endl;
}
下标
可以理解:从0下标对应位置开始,0下标存的是指针6,6下标对应值3;值3对应对应指针8,8下标对应值5;值5对应指针3,3下标对应值8,,,,
5.希尔排序(缩小增量排序)
希尔排序在前面几种插入方式的基础上,在时间效率上有所提高
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序
#define MAXSIZE 20
#define T int
typedef T Seqlist[MAXSIZE];
void swap(T *a,T *b)
{
T temp = *a;
*a = *b;
*b = temp;
}
void Shell_insert(Seqlist &L,int n,int dis)//dis为增量的值
{
for(int i=dis+1;i<n;++i)
{
if(L[i]<L[i-dis])
{
//L[0] = L[i];
//for()
swap(&L[i],&L[i-dis]);
}
}//L[i-dis] = L[0];
}
void Shell_sort(Seqlist &L,int n,int gap_data[],int t) //希尔排序
{
for(int k = 0;k<t;++k)
{
Shell_insert(L,n,gap_data[k]);
}
}
希尔排序测试文件
void main()
{
//Seqlist L = {0,49,38,65,97,76,13,27,49};
Seqlist L = {0,16,24,8,25,21,3,49,5};
int n = 9;
//int gap_data[]={5,4,2,1}; //注意由于间距的取值,有时候希尔排序得到的并非是完全正确的排序
int gap_data[]={4,2,1}; //3 8 5 16 21 24 25 25 49
int t = sizeof(gap_data)/sizeof(int);
Shell_sort(L,n,gap_data,t);
for(int i = 1;i < 9;++i) //注意:此时L[0]储存的是临时对象的值
{
cout<<L[i]<<" ";
}
}
注意:希尔排序的间距的取值,一般为:gap = gap/3 + 1;
或:gap = n/2 ;gap = gap/2;
对于规模较大的序列(n<1000),希尔排序具有较高的效率,且代码实现简单,所以应用较广