数据结构与算法中排序详解!!!
本文是总结中国大学mooc上的电子科技大学的数据结构和算法课程,未完待续!
排序的基本概念(稳定排序与不稳定排序)
**稳定的排序方法:**对于任意的数据元素序列,若排序前后所有相同关键字的相对位置都不变。
**不稳定的排序方法:**若存在一组数据序列,在排序前后,相同关键字的相对位置发生了变化。
举个栗子~
比如有一组序列:4,3,3,2
排序后变成了:2,3,3,4。这就是不稳定的排序。
我们先来看简单的排序方法:
插入排序:
简单插入排序:
思想:将无序子序列中的一个或几个记录“插入”到有序子序列中,从而增加有序子序列的长度。
就是先从无序子序列中顺次取一个数,放入有序子序列中并排序。
步骤:定位(查找要插入的数的位置)->挤空(所有记录向后移一位)->插入
由于定位方法的不同可以将插入排序分类:
1.直接插入排序(基于顺序查找定位)
2.折半插入排序(基于折半查找定位)
3.希尔排序(基于逐趟缩小增量)
下面我们分别介绍这三种排序方式:
直接插入排序:整个排序过程为n-1趟插入,先将序列中第一个记录看成是一个有序子序列,然后从第二个记录开始,逐个进行插入,直至整个序列有序。
这个比较简单,就不图示了,下面给出算法实现:
#include <stdio.h>
#include <string.h>
typedef struct{
int key;
float info;
}JD;
//直接插入排序
//对长度为n的序列排序
void straisort(JD r[],int n)
{
int i,j;
for(i=2;i<=n;i++){
r[0]=r[i];
j=i-1;
while(r[0].key<r[j].key)
{
r[j+1]=r[j];
j--;
}
r[j+1]=r[0];
}
}
选择排序:
简单选择排序:
思想:从无序子序列中“选择”关键字最大或最小的记录,并将它加入到有序子序列中,以此方法增加记录中有序子序列的长度。
相比于简单插入排序,增加的步骤就是在无序序列中要进行选择一次。
排序过程:
首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换。
再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换
重复上述操作,共进行n-1趟排序。
void smp_selesort(JD r[],int n){
int i,j,k;
JD x;
for(i=1;i<n;i++){
k=i;
for(j=i+1;j<=n;j++)
if (r[j].key<r[k].key)
k=j;
if(i!=k){
x=r[i];
r[i]=r[k];
r[k]=x;
}
}
}
交换排序:
通过“交换”无序序列中的记录从而得到其中关键字最大/最小的记录,并将它加入到有序子序列中,以此方法增加有序子序列长度。
- 冒泡排序
- 快速排序
首先说冒泡排序:
排序过程:
1.将第一个记录的关键字与第二个记录的关键字进行比较,若为逆序r[1].key>r[2].key,则交换;然后比较第二个记录和第三个记录,依次类推。直至第n-1个记录和第n个记录比较为止,第一趟冒泡排序,结果关键字最大的记录被安置在最后一个记录上。
2.对前n-1个记录进行第二次冒泡排序,结果使关键字次大的记录被安置在第n-1个记录位置。
3.重复上述过程,直到“在一趟排序过程中没有进行过交换记录的操作”为止
//冒泡排序
void bubble_sort(JD r[],int n)
{
//flag表示本趟有无交换
int m,i,j,flag=1;
JD X;
m=n;
while ((m>1)&&(flag==1))//趟数
{
flag=0;
for(j=1;j<m;j++)
if (r[j].key>r[j+1].key)
{
flag=1;
x=r[j];
r[j]=r[j+1];
r[j+1]=x;
}
m--;
}
}
一般情况下,每经过一趟“冒泡”,“m-1”,但并不是每趟如此。
所以对冒泡排序进行改进:
//改进冒泡排序,m
void BubbleSort(Elem R[],int n)
{
int m;
m=n;
while(m>1){
lastExchangeIndex=1;
for(j=1;j<m;j++)
if(R[j].key>R[j+1].key){
swap(R[j],R[j+1]);
lastExchangeIndex=j;//记下进行交换的记录位置
}
m=lastExchangeIndex;//本趟最后一次交换位置
}
}
快速排序:
实际使用中已知的最快的排序方法
重点在于选择枢纽pivot,使得A1和A2子集合数据相当。
我们采用三种取中法,Pivot=median(left,center,right)
以选择第一个关键字为枢纽为例:
排序过程:
1.对r[s…t]中记录进行一趟快速排序,附设两个指针i和j,设划分元记录rp=r[s],x=rp.key
2.初始时令i=s,j=t
3.首先从j所指位置向前搜索第一个关键字小于x的记录,并和rp交换。
再从i所指的位置起向后搜索,找到第一个关键字大于x的记录,和rp交换。
4.重复上述两步,直到i==j为止。
5.再分别对两个子序列进行快速排序,直到每个子序列只含有一个记录为止。
void qksort(JD r[],int t,int w)
{
//t=low,w=high
int i,j,k;
JD x;
if (t>=w) return;
i=t,j=w,x=r[i].key;
while(i<j)
{
while((i<j)&&(r[j].key>=x.key))
j--;//枢纽后面的值大于枢纽
//当不满足的时候,与枢纽交换
if(i<j){
r[i]=r[j];
i++;
}
//枢纽前面的值小于枢纽
while((i<j)&&(r[i].key<=x.key))
i++;
if(i<j){
r[j]=r[i];
j--;
}
r[i].key=x;
qksort(r,t,j-1);
qksort(r,j+1,w);
}
}