1.插入排序
(1)直接插入排序
从第一个元素开始,该元素可以认为已经被排序;
取出下一个元素,在已经排序的元素序列中从后向前扫描;
如果该元素(已排序)大于新元素,将该元素移到下一位置;
重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
将新元素插入到该位置后;
重复步骤2~5。
原始序列:49 38 65 97 13 27 49
第1次: 38 49 65 97 13 27 49
第2次: 38 49 65 97 13 27 49
第3次: 38 49 65 97 13 27 49
第4次: 13 38 49 65 97 27 49
第5次: 13 27 38 49 65 97 49
第6次: 13 27 38 49 49 65 97
时间复杂度O(n2)
代码:
/*直接插入排序*/
void insertSort(int list[], int n)
{
int i = 1, j = 0, node = 0, count = 1;
printf("对序列进行直接插入排序:\n");
printf("初始序列为:");
printList(list, n);
for(i = 2; i <= n; i++)
{
node = list[i];
j = i - 1;
while(j >= 0 && node < list[j])
{
list[j+1] = list[j];
--j;
}
list[j+1] = node;
printf("第%d次排序结果:", count++);
printList(list, n);
}
}
(2).折半插入排序
设待排序的记录存放在数组r[1…n]中,r[1]是一个有序序列。
循环n-1次,每次使用折半查找法,查找r[i](i=2,…,n)在已排好的序列r[1…i-1]中的插入位置,然后将r[i]插入表长为i-1的序列r[1…i-1],直到将r[n]插入表长为n-1的有序序列r[1…n-1],最后得到一个表长为n的有序序列。
时间复杂度仍为O(n2)
void BinsertSort(int slist[],int n)
{
int i,j,low,high,mid,node;
for(int i=2; i<=n; i++)
{
node=slist[i];
low=1;
high=i-1;
while(low<=high)
{
mid=(low+high)/2;
if(node<slist[mid])
high=mid-1;
else
low=mid+1;
}
for(j=i-1; j>=low; j--)
slist[j+1]=slist[j];
slist[low]=node;
printf("第%d次排序结果:", cnt++);
printList(slist, n);
}
}
2.希尔排序
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
过程:(48 16 92 65 32 65 27 23)
1.首先,增量d1=4,将序列分割为4个子序列,{R1,R5}{R2,R6}{R3,R7}{R4,R8}分别对每个子序列插入排序
2.增量d2=2,分别对两个子序列{R1,R3,R5,R7}{R2,R4,R6,R8}进行直接插入排序
3.增量d3=1,对整个记录进行一次直接插入排序。
代码:
void ShellSort(int slist[],int n) //希尔排序
{
int i,j,d;
for(d=n/2; d>0; d/=2)
{
for(i=d+1; i<=n; i++)
{
if(slist[i]<slist[i-d])
{
slist[0]=slist[i];
for(j=i-d; j>0&&slist[j]>slist[0]; j-=d)
slist[j+d]=slist[j];
slist[j+d]=slist[0];
}
}
printf("第%d次排序结果:", count++);
printList(slist, n);
}
}
3.冒泡排序
比较相邻的元素。如果第一个比第二个大,就交换它们两个;
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
针对所有的元素重复以上的步骤,除了最后一个;
重复步骤1~3,直到排序完成。
void BubbleSort(int list[],int n) //冒泡排序
{
int i,j,flag,temp;
for(j=1; j<=n-1; j++)
{
flag=0;
for(i=1; i<=n-j; i++) //对无序区扫描
{
if(list[i]>list[i+1])
flag=1,temp=list[i],list[i]=list[i+1],list[i+1]=temp;
}
if(flag==0) //本趟排序未交换,提前终止算法
break;
printf("第%d次排序结果:", count++);
printList(list,n);
}
return ;
}
4.快速排序
1.初始化:取第一个记录R1作为枢纽,设置两个指针i,j分别用来指示将要与基准进行比较的左侧记录和右侧记录的位置。
2.用枢纽记录与j指向的记录比较,如果j指向的比枢纽大,j减1,继续比较,直到比枢纽小,那么将j指向的记录移动到i所指的位置。
3.用枢纽记录与指针i+1指向的记录比较,如果i指向的记录的关键字值小,则i+1,继续比较,直到i指向的记录的关键字值比枢纽记录大,那么将i指向的记录移动到j指向的位置。
4.重复2和3,直到i==j,这时候i就是枢纽的最终位置。
初始序列: 46 16 89 65 34 65 23 28
第一次移动:28 16 89 65 34 65 23
第二次移动:28 16 65 34 65 23 89
第三次移动:28 16 23 65 34 65 89
第四次移动:28 16 23 34 65 65 89
第五次移动:28 16 23 34 65 65 89
第一趟快排:28 16 23 34 46 65 65 89
第二趟快排:23 16 28 34 46 65 65 89
第三趟快排:16 23 28 34 46 65 65 89
第四趟快排:16 23 28 34 46 65 65 89
第五趟快排:16 23 28 34 46 65 65 89
当初始序列基本有序时,退化成冒泡排序,快排的平均时间复杂度为O(nlog2n)
代码:
void quick_sort(int a[],int l,int r,int n) //快速排序
{
int k=a[l];
if(l<r)
{
int i=l,j=r;
while(i<j)
{
while(a[j]>=k&&i<j) j--;
a[i]=a[j];
while(a[i]<=k&&i<j) i++;
a[j]=a[i];
}
a[i]=k;
printf("第%d次排序结果:", count++);
printList(a,n);
quick_sort(a,l,i-1,n); //递归左区间
quick_sort(a,i+1,r,n); //递归右区间
}
}
5.选择排序
每经过一次比较就找出一个最小值,与待排序序列最前面的位置互换即可。
代码:
void SelectSort(int a[],int n) //选择排序
{
int i,j,minn;
int temp;
for(i=1;i<n;i++)
{
minn=i;
for(j=i+1;j<=n;j++)
if(a[i]>a[j])
minn=j;
if(minn!=i)
temp=a[i],a[i]=a[minn],a[minn]=temp;
printf("第%d次排序结果:", count++);
printList(a,n);
}
return ;
}
6.堆排序
堆:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
过程:将n个无序的记录建成一个堆,此时选出堆中所有记录的最大值或最小值,然后输出堆顶元素,(每次都用堆顶元素和最后一个非终端节点开始逐步往前交换)将剩余的n-1个元素重新建成一个堆,输出次大值。
代码:
/*堆排序*/
void heapAdjust(int list[], int u, int n)
{
int node=list[u];
for(int j=2*u; j<=n; j*=2) //向下筛选
{
if(list[j]<list[j+1]&&j+1<=n)
j++; //j为左右孩子中较大的那个的下标
if(node>list[j])
break;
list[u]=list[j]; //调整到位
u=j;
}
list[u]=node;
}
void heapSort(int list[], int n)
{
int i,temp;
printf("请输出初始堆:");
for(i=n/2; i>0; i--)
heapAdjust(list,i,n);
//要使每个非终端结点都大于他的左右孩子,直到根节点为止,n个节点的完全二叉树的最后一个非终端节点编号必为n/2,所以从下标为n/2的节点开始调整,建成大根堆
printList(list,n);
for(i=n; i>1; i--)
{
temp=list[i];
list[i]=list[1];
list[1]=temp; //堆顶与堆底交换
printf("第%d次排序结果:", count++);
heapAdjust(list,1,i-1); //重建堆
printList(list,n);
}
}
7.归并排序
过程:假设初始序列含有n个记录,可看成有n个有序子序列,每个子序列长度为1,然后两两归并,得到n/2个长度为2的子序列,再两两归并,一直到得到一个长度为n的有序表为止。归并排序需要一个数组来存改变后的状态。
时间复杂度为O(nlog2n)
代码:
void Merge(int a[],int l,int r,int m,int n)
{
int i=l,j=m+1,k=l;
int temp[MAX];
while(i<=m&&j<=r)
{
if(a[i]>a[j])
temp[k++]=a[j++];
else
temp[k++]=a[i++];
}
while(i<=m)
temp[k++]=a[i++];
while(j<=r)
temp[k++]=a[j++];
for(i=l;i<=r;i++)
a[i]=temp[i];
printf("第%d次排序结果:", count++);
printList(a,n);
}
void MergeSort(int a[],int l,int r,int n) //归并排序
{
if(l<r)
{
int mid=(l+r)/2;
MergeSort(a,l,mid,n); //递归分成只有1个数的小区间
MergeSort(a,mid+1,r,n);
Merge(a,l,r,mid,n);
}
}
8.基数排序
通过基数排序对数组{53, 3, 542, 748, 14, 214, 154, 63, 616},它的示意图如下:
在上图中,首先将所有待比较树脂统一为统一位数长度,接着从最低位开始,依次进行排序。
- 按照个位数进行排序。
- 按照十位数进行排序。
- 按照百位数进行排序。
排序后,数列就变成了一个有序序列。
代码还不会写~
排序方法 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
直接插入排序 | O(n2) | O(1) | 稳定 |
希尔排序 | O(n1.3) | O(1) | 不稳定 |
简单选择排序 | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(1) | 不稳定 |
冒泡排序 | O(n2) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(log2n)~O(n) | 不稳定 |
归并排序 | O(nlog2n) | O(n) | 稳定 |
基数排序 | O(d(n+r)) | O(n+r) | 稳定 |
七种排序的代码及调用
#include <stdlib.h>
#include <stdio.h>
#include<algorithm>
#define MAX 50
int slist[MAX]; /*待排序序列*/
int count;
void insertSort(int list[], int n);
void createList(int list[], int *n);
void printList(int list[], int n);
void heapAdjust(int list[], int u, int v);
void heapSort(int list[], int n);
/*直接插入排序*/
void insertSort(int list[], int n)
{
int i = 1, j = 0, node = 0, count = 1;
printf("对序列进行直接插入排序:\n");
printf("初始序列为:");
printList(list, n);
for(i = 2; i <= n; i++)
{
node = list[i];
j = i - 1;
while(j >= 0 && node < list[j])
{
list[j+1] = list[j];
--j;
}
list[j+1] = node;
printf("第%d次排序结果:", count++);
printList(list, n);
}
}
/*堆排序*/
void heapAdjust(int list[], int u, int n)
{
int node=list[u];
for(int j=2*u; j<=n; j*=2)
{
if(list[j]<list[j+1]&&j+1<=n)
j++;
if(node>list[j])
break;
list[u]=list[j];
u=j;
}
list[u]=node;
}
void heapSort(int list[], int n)
{
int i,temp;
printf("请输出初始堆:");
for(i=n/2; i>0; i--)
heapAdjust(list,i,n);
printList(list,n);
for(i=n; i>1; i--)
{
temp=list[i];
list[i]=list[1];
list[1]=temp;
printf("第%d次排序结果:", count++);
heapAdjust(list,1,i-1);
printList(list,n);
}
}
void ShellSort(int slist[],int n) //希尔排序
{
int i,j,d;
for(d=n/2; d>0; d/=2)
{
for(i=d+1; i<=n; i++)
{
if(slist[i]<slist[i-d])
{
slist[0]=slist[i];
for(j=i-d; j>0&&slist[j]>slist[0]; j-=d)
slist[j+d]=slist[j];
slist[j+d]=slist[0];
}
}
printf("第%d次排序结果:", count++);
printList(slist, n);
}
}
void quick_sort(int a[],int l,int r,int n) //快速排序
{
int k=a[l];
if(l<r)
{
int i=l,j=r;
while(i<j)
{
while(a[j]>=k&&i<j) j--;
a[i]=a[j];
while(a[i]<=k&&i<j) i++;
a[j]=a[i];
}
a[i]=k;
printf("第%d次排序结果:", count++);
printList(a,n);
quick_sort(a,l,i-1,n);
quick_sort(a,i+1,r,n);
}
}
void BubbleSort(int list[],int n) //冒泡排序
{
int i,j,flag,temp;
for(j=1; j<=n-1; j++)
{
flag=0;
for(i=1; i<=n-j; i++)
{
if(list[i]>list[i+1])
flag=1,temp=list[i],list[i]=list[i+1],list[i+1]=temp;
}
if(flag==0)
break;
printf("第%d次排序结果:", count++);
printList(list,n);
}
return ;
}
void SelectSort(int a[],int n) //选择排序
{
int i,j,minn;
int temp;
for(i=1; i<n; i++)
{
minn=i;
for(j=i+1; j<=n; j++)
if(a[i]>a[j])
minn=j;
if(minn!=i)
temp=a[i],a[i]=a[minn],a[minn]=temp;
printf("第%d次排序结果:", count++);
printList(a,n);
}
return ;
}
void Merge(int a[],int l,int r,int m,int n)
{
int i=l,j=m+1,k=l;
int temp[MAX];
while(i<=m&&j<=r)
{
if(a[i]>a[j])
temp[k++]=a[j++];
else
temp[k++]=a[i++];
}
while(i<=m)
temp[k++]=a[i++];
while(j<=r)
temp[k++]=a[j++];
for(i=l; i<=r; i++)
a[i]=temp[i];
printf("第%d次排序结果:", count++);
printList(a,n);
}
void MergeSort(int a[],int l,int r,int n) //归并排序
{
if(l<r)
{
int mid=(l+r)/2;
MergeSort(a,l,mid,n); //递归分成只有1个数的小区间
MergeSort(a,mid+1,r,n);
Merge(a,l,r,mid,n);
}
}
/*生成待排序序列*/
void createList(int list[], int *n)
{
int i = 1,a;
printf("请输入待排序序列(长度小于50,以输入一个字符结束):\n");
while(scanf("%d",&a)==1)
{
list[i] = a;
i++;
}
*n=i-1;
getchar();
}
/*输出排序结果*/
void printList(int list[], int n)
{
int i = 1;
for(; i <= n; i++)
{
printf("%d ", list[i]);
if(i % 10 ==0 && i != 0)
printf("\n");
}
printf("\n");
}
int main()
{
int choice=1,length;
while(choice!=0)
{
count=1;
printf("\n");
printf("***** 内部排序算法演示程序 *****\n");
printf("\n1. 直接插入排序 \n");
printf("\n2. 堆排序 \n");
printf("\n3. 希尔排序 \n");
printf("\n4. 快速排序 \n");
printf("\n5. 冒泡排序 \n");
printf("\n6. 选择排序 \n");
printf("\n7. 归并排序 \n");
printf("\n0. 退出\n");
printf("\n请选择:");
scanf("%d", &choice);
getchar();
switch(choice)
{
case 1:
{
createList(slist, &length);
insertSort(slist, length);
break;
}
case 2:
{
createList(slist, &length);
heapSort(slist, length);
break;
}
case 3:
{
createList(slist, &length);
ShellSort(slist,length);
break;
}
case 4:
{
createList(slist, &length);
quick_sort(slist,1,length,length);
break;
}
case 5:
{
createList(slist, &length);
BubbleSort(slist, length);
break;
}
case 6:
{
createList(slist, &length);
SelectSort(slist, length);
break;
}
case 7:
{
createList(slist, &length);
MergeSort(slist,1,length,length);
break;
}
default:
choice=0;
}
printf("\n");
}
return 0;
}