直接插入排序(顺序存储、链式存储),折半插入排序(顺序存储),希尔排序(顺序存储)
插入排序
直接插入排序
将元素插入L[i]插入到已有序的子序列L[i-1]中。其基本思想是每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成。基本步骤如下:
1)查找出L[i]在L[1]~L[i-1]中要插入的位置K;
2)将L[i]的值复制到L[0];
3)将L[K]~L[i-1]中的所有元素依次后移一个位置;
4)将L[0]的值复制到L[K];
空间复杂度:O(1)
最好时间复杂度(全部有序):O(n)
最坏时间复杂度(全部逆序):O(n^2)
平均时间复杂度:O(n2)
算法稳定性:稳定
折半插入排序
顺序存储的线性表可以用折半查找来实现。用折半查找来确定待插入的位置后,就可以统一的向后移动元素。基本步骤如下:
1)当 low>high 时折半查找停止,应将 [low, i-1] 内的元素全部右移,并将 A[0] 复制到 low 所指位置;
2)当 A[mid]==A[0] 时,为了保证算法的“稳定性”,应继续在 mid 所指位置右边寻找插⼊位置。
空间复杂度:O(1)
时间复杂度:移动元素的次数变少了,但是关键字对比的次数依然是O(n2) 数量级,整体来看时间复杂度依然是O(n^2)
算法稳定性:不稳定
顺序存储结构
/*
Project:InsertSort(直接插入排序)
Data:2020/11/18
Author:F&S&L
InitList(SqList &L) 参数:顺序表L
CreateList(SqList &L,int n) 参数:顺序表L,顺序表中元素个数n
InitList(SqList &L) 参数:顺序表L
Create(SqList &L) 参数:顺序表L
InsertSort(SqList &L) 参数:顺序表L
HalfInsertSort(SqList &L) 参数:顺序表L
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define MaxSize 100
#define ElemType int
#define Status int
using namespace std;
//顺序表数据结构
typedef struct
{
ElemType data[MaxSize];
int length;
} SqList;
//初始化顺序表函数,构造一个空的顺序表
Status InitList(SqList &L)
{
memset(L.data,0,sizeof(L));
L.length=0;
return 0;
}
//打印输出顺序表
void PrintList(SqList L)
{
for(int i=1;i<L.length+1;i++)
{
printf("%d ",L.data[i]);
}
printf("\n");
}
//初始化顺序表函数
bool CreateList(SqList &L,int n)
{
if(n<0||n>MaxSize)false;
for(int i=1;i<n+1;i++)
{
scanf("%d",&L.data[i]);
L.length++;
}
return true;
}
//创建顺序表函数
void Create(SqList &L)
{
int n;
bool flag;
printf("请输入要创建的顺序表长度(>1):");
scanf("%d",&n);
printf("请输入%d个数(空格隔开):",n);
flag=CreateList(L,n);
if(flag)
{
printf("创建成功后的元素:");
PrintList(L);
}
else printf("输入长度非法!!!\n");
}
//直接插入排序 ,升序排序
void InsertSort(SqList &L)
{
int i,j;
for (i=2;i<L.length+1;i++)
{
if(L.data[i]<L.data[i-1])
{
L.data[0]=L.data[i];
L.data[i]=L.data[i-1];
for(j=i-2;L.data[0]<L.data[j];j--)
{
L.data[j+1]=L.data[j];
}
L.data[j+1]=L.data[0];
}
}
printf("直接插入排序后的元素:") ;
PrintList(L);
}
//折半插入排序
void HalfInsertSort(SqList &L)
{
int i,j,low,high,mid;
for(i=2;i<L.length+1;i++)
{
L.data[0]=L.data[i];
low=1;
high=i-1;
while(low<=high)
{
mid=(low+high)/2;
if(L.data[mid]>L.data[0])high=mid-1;
else low=mid+1;
}
for(j=i-1;j>=high+1;j--)
{
L.data[j+1]=L.data[j];
}
L.data[high+1]=L.data[0];
}
printf("折半插入排序后的元素:");
PrintList(L);
}
//主函数
int main()
{
SqList L;
InitList(L);
Create(L);
InsertSort(L);
HalfInsertSort(L);
}
链式存储结构
/*
Project:LinkInsertSort(直接插入排序)
Data:2020/11/18
Author:F&S&L
InitList(LinkList &L) 参数:链表L
ListLength(LinkList L) 参数:链表L
InsertList(LinkList &L,ElemType e) 参数:链表L,待插入元素e
PrintList(LinkList L) 参数:链表L
Sort(LinkList &L) 参数:链表L
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define Status int
#define ElemType int
//单链表数据结构
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化一个带头结点的空链表
Status InitList(LinkList &L)
{
L=new LNode;
L->next=NULL;
return 1;
}
//获取单链表长度,头结点无数据,不算
int ListLength(LinkList L)
{
LinkList p=L;
int sum=0;
while(p)
{
sum++;
p=p->next;
}
return sum-1;
}
// 按升序插入函数
bool InsertList(LinkList &L,ElemType e)
{
LNode* s;
LinkList r=L,p=L->next;
s=new LNode;
s->data=e;
while(p) //当结点p不为空
{
if(p->data<e)
{
r=r->next;
p=p->next;
}
else
{
s->next=p;
r->next=s;
break;
}
}
s->next=p;
r->next=s;
return true;
}
//打印输出函数
void PrintList(LinkList L)
{
LinkList p=L->next;
if(ListLength(L))
{
while(p)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
else
{
printf("当前单链表已空!!!\n");
}
}
//排序实现函数 ,调用InsertList
void Sort(LinkList &L)
{
int flag;
ElemType e;
printf("请输入要插入的元素:");
scanf("%d",&e);
flag=InsertList(L,e);
if(flag)
{
printf("排序后的元素:");
PrintList(L);
}
}
//菜单
void menu()
{
printf("***************1.插入 2.退出***************\n");
}
//主函数
int main()
{
LinkList L;
InitList(L);
int choice;
while(1)
{
menu();
printf("请输入菜单号:");
scanf("%d",&choice);
if(choice==2)
break;
switch(choice)
{
case 1:Sort(L);break;
default:printf("输入错误!!!\n");
}
}
return 0;
}
希尔排序
先将待排序表分割成若干形如 L[i, i + d, i + 2d,…, i + kd] 的“特殊”子表,对各个子表分别进行直接插⼊排序。缩小增量d,重复上述过程,直到d=1为止。仅适用于顺序表,不适用于链表。
空间复杂度:O(1)
时间复杂度:和增量序列 d1, d2, d3… 的选择有关,目前无法用数学手段证明确切的时间复杂度 最坏时间复杂度为 O(n^2),当n在某个范围内时,可达O(n1.3)
稳定性:不稳定
/*
Project:ShellSort(希尔排序)
Data:2020/11/18
Author:F&S&L
InitList(SqList &L) 参数:顺序表L
CreateList(SqList &L,int n) 参数:顺序表L,顺序表中元素个数n
PrintList(SqList L) 参数:顺序表L
Create(SqList &L) 参数:顺序表L
ShellSort(SqList &L) 参数:顺序表L
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define MaxSize 100
#define ElemType int
#define Status int
using namespace std;
//顺序表数据结构
typedef struct
{
ElemType data[MaxSize];
int length;
}SqList;
//初始化顺序表函数,构造一个空的顺序表
Status InitList(SqList &L)
{
memset(L.data,0,sizeof(L));
L.length=0;
return 1;
}
//初始化顺序表函数
bool CreateList(SqList &L,int n)
{
if(n<0||n>MaxSize)false;
printf("请依次输入%d个元素(空格隔开):",n);
for(int i=1;i<=n;i++)
{
scanf("%d",&L.data[i]);
L.length++;
}
return true;
}
//打印输出函数
void PrintList(SqList L)
{
for(int i=1;i<=L.length;i++)
{
printf("%d ",L.data[i]);
}
printf("\n");
}
//创建顺序表实现函数,调用 CreateList
void Create(SqList &L)
{
int n;
bool flag;
printf("请输入要创建的顺序表长度:");
scanf("%d",&n);
flag=CreateList(L,n);
if(flag)
{
printf("顺序表为:");
PrintList(L);
}
}
//希尔排序函数
void ShellSort(SqList &L)
{
int d,i,j;
for(d=L.length/2;d>=1;d=d/2)
{
for(i=d+1;i<=L.length;i++)
{
if(L.data[i]<L.data[i-d])
{
L.data[0]=L.data[i];
for(j=i-d;j>0&&L.data[j]>L.data[0];j-=d)L.data[j+d]=L.data[j];
L.data[j+d]=L.data[0];
}
}
}
printf("希尔排序后的顺序表:");
PrintList(L);
}
//主函数
int main()
{
SqList L;
InitList(L);
Create(L);
ShellSort(L);
}