排序的基本概念
- 排序就是整理表中的元素,使之按关键字递增或递减有序排序。
- 如果待排序的表中存在有多个关键字相同的元素,经过排序后这些具有相同关键字的元素之间的相对次序保持不变,则称这种排序方法是稳定的;反之,若具有相同关键字的元素之间的相关次序发生变化,则称这种排序方法是不稳定的。
- 在排序过程中,若整个表都放在内存中处理,排序时不涉及数据的内,外存交换,则称之内排序;反之,若在排序过程要进行数据的内,外存交换,则称之为外排序。
待排序的顺序表中数据元素的类型声明:
typedef int KeyType; //定义关键字类型为int
typedef struct{ //元素类型
KeyType key; //关键字项
InfoType data; //其他数据项,类型为InfoType
} RecType; //排序元素的类型
插入排序
直接插入排序
void InsertSort(RecType R[],int n){ //对R[0……n-1]按递增有序进行直接插入排序
int i,j;
RecType tmp;
for(i=1;i<n;i++){
if(R[i].key<R[i-1].key){ //反序时
tmp=R[i];
j=i-1;
do{ //找R[i]的插入位置
R[j+1]=R[j]; //将关键字大于R[i].key的记录后移
j--;
}while (j>=0&&R[j].key>tmp.key);
R[j+1]=tmp; //在j+1处插入R[i]
}
}
}
折半插入排序
void BinInsertSort(RecType R[],int n){
int i,j,low,high,mid;
RecType tmp;
for(i=1.i<n;i++){
if(R[i].key<R[i-1].key){ //反序时
tmp=R[i]; //将R[i]保存到tmp中
low=0;
high=i-1;
while(low<=high){ //在R[low……high]中查找插入的位置
mid=(low+high)/2; //取中间位置
if(tmp.key<R[mid].key)
high=mid-1; //插入点在左半区
else
low=mid+1; //插入点在右半区
} //找位置high
for(j=i-1;j>=high+1;j--) //集中进行元素后移
R[j+1]=R[j];
R[high+1]=tmp; //插入tmp
}
}
}
希尔排序
void ShellSort(RecType R[],int n){ //希尔排序算法
int i,j,d;
RecType tmp;
d=n/2; //增量置初值
while(d>0){
for(i=0;i<n;i++){ //对所有组采用直接插入排序
tmp=R[i]; //对相隔d个位置一组采用直接插入排序
j=i-d;
while(j>=0&&tmp.key<R[i].key){
R[j+d]=R[j];
j=j-d;
}
R[j+d]=tmp;
}
d=d/2; //减小增量
}
}
交换排序
冒泡排序
void BubbleSort(RecType R[],int n){
int i,j;
for(i=0;i<n-1;i++)
for(j=n-1;j>i;j--) //将R[i]元素归位
if(R[j].key<R[j-1].key) //相邻的两个元素反序时
swap(R[j],R[j-1]); //将R[j]和R[j-1]两个元素交换
}
快速排序
int partition(RecType R[],int s,int t){ //一趟划分
int i=s,j=t;
RecType tmp=R[i]; //以R[i]为基准
while(i<j){ //从两端交替向中间扫描,直至i=j为止
while(j>i&&R[i].key>=tmp.key)
j--; //从右向左扫描,找一个小于tmp.key的R[i]
R[i]=R[j]; //找到这样的R[j],放在R[i]处
while(i<j&&R[i].key<=tmp.key)
i++ //从左向右扫描,找一个大于tmp.key的R[i]
R[j]=R[i]; //找到这样的R[i],放入R[j]处
}
R[i]=tmp;
return i;
}
void QuickSort(RecType R[],int s,int t){ //对R[s……t]的元素进行快速排序
int i;
if(s<t){ //区间内至少存在两个元素的情况
i=partition(R,s,t);
QuickSort(R,s,i-1); //对左区间递归排序
QuickSort(R,i+1,t); //对右区间递归排序
}
}
选择排序
简单选择排序
void SelectSort(RecType R[],int n){
int i,j,k;
for(i=0;i<n-1;i++){ //做第i趟排序
k=i;
for(j=i+1;j<n;j++) //在当前无序区R[i……n-1]中选key最小的R[k]
if(R[j].key<R[k].key)
k=j; //k记下目前找到的最小关键字所在的位置
if(k!=i) //R[i]和R[k]两个元素交换
swap(R[i],R[K]);
}
}
堆排序
void HeapSort(RecType R[],int n){
int i;
for(i=n/2;i>=1;i--) //循环建立初始堆,调用sift算法(n/2)次
sift(R,i,n);
for(i=n;i>=2;i--){ //进行n-1趟完成堆排序,每一趟堆中元素个数减1
swap(R[1],R[i]); //将最后一个元素与根R[1]交换
sift(R,1,i-1); //对R[1……i-1]进行筛选,得到i-1个结点的堆
}
}
归并排序
归并排序是多次将两个或两个以上的有序表合并成一个新的有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表,即二路归并。
void Merge(RecType R[],int low,int mid,int high) 归并R[low……high]
{
RecType *R1;
int i=low,j=mid+1,k=0; //k是R1的下标,i,j分别为第1,2段的下标
R1=(RecType *)malloc((high-low+1)*sizeof(RecType));
while(i<=mid&&j<=high) //在第1段和第2段均未扫描完时循环
if(R[i].key<=R[j].key){ //将第1段中的元素放入R1中
R1[k]=R[i];
i++;
k++;
}
else{ //将第2段中的元素放入R1中
R1[k]=R[j];
j++;
k++;
}
while(i<=mid){ //就第1段余下的部分复制到R1
R1[k]=R[j];
i++;
k++;
}
while(j<=high){ //将第2段余下的部分复制到R1
R1[k]=R[j];
j++;
k++;
}
for(k=0,i=low;i<=high;k++,i++) //将R1复制到R[low……high]中
R[i]=R1[k];
free(R1);
}
基数排序
基数排序是通过分配和收集过程来实现排序,不需要进行关键字间的比较,是一种借助于多关键字排序的思想对单关键字排序的方法。
typedef struct node{
char data[MAXD]; //MAXD为最大的关键字位数
struct node *next; //指向下一个结点
} NodeType; //基数排序数据的结点类型
void RadixSort(NodeType *&p,int r,int d){ //LSD基数排序算法
NodeType *head[MAXR],*tail[MAXR],*t; //定义各链队的首尾指针
int i,j,k;
for(i=0;i<=d-1;i++){ //从低位到高位循环
for(j=0;i<r;j++) //初始化各链队的首,尾指针
head[j]=tail[j]=NULL;
while(p!=NULL){ //分配:对于原链表中的每个结点循环
k=p->data[i]-'0'; //找第k个链队
if(head[k]==NULL){ //第k个链队空时,队头,队尾均指向结点p
head[k]=p;
tail[k]=p;
}
else{ //第k个链队非空时结点p进队
tail[k]->next=p;
tail[k]=p;
}
p=p->next; //取下一个待排序的元素
}
p=NULL; //重新用p来收集所有结点
for(j=0;j<r;j++) //收集:对于每一个链队循环
if(head[j]!=NULL){ //若第j个链队是第一个非空链队
if(p==NULL){
p=head[j];
t=tail[j];
}
else{ //若第j个链队是其他非空链队
t->next=head[j];
t=tail[j];
}
}
t->next=NULL; //最后一个结点的next域置NULL
}
}