#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
typedef int Status;
typedef int ElemType;
typedef struct SqList{
ElemType *elem;
int length;
}SqList;
Status CreateList_Sq(SqList & ); //构建
void Load_Sq(SqList ); //遍历打印
//插入排序
void InsertSort(SqList & ); //直接插入排序
void BInsertSort(SqList & ); //折半插入排序
void ShellSort(SqList & ); //希尔排序
//交换排序
void BubbleSort(SqList & ); //冒泡排序
int Partition(SqList & , int , int ); //一趟
void QuickSort(SqList & , int , int ); //快速排序(递归)
//选择排序
void SelectSort(SqList & ); //简单选择排序
void HeapAdjust(SqList & , int , int ); //初始堆、调整堆
void HeapSort(SqList & ); //堆排序
//归并排序
void Merge(SqList & , SqList & , int , int , int );
void MergeSort(SqList & );
int main()
{
SqList L;
int a;
if(!CreateList_Sq(L)) printf("Create Error!\n");
printf("插入排序:\n1:直接插入排序\n2:折半插入排序\n3:希尔排序\n");
printf("交换排序:\n4:冒泡排序\n5:快速排序\n");
printf("选择排序:\n6:简单选择排序\n7:堆排序\n");
printf("归并排序:\n8:2路归并排序\n");
printf("请选择:\n");
scanf("%d", &a);
switch(a)
{
case 1: InsertSort(L); break;
case 2: BInsertSort(L); break;
case 3: ShellSort(L); break;
case 4: BubbleSort(L); break;
case 5: QuickSort(L,1,L.length); break;
case 6: SelectSort(L); break;
case 7: HeapSort(L); break;
case 8: MergeSort(L); break;
}
return 0;
}
Status CreateList_Sq(SqList &L)
{
int n, i;
printf("请输入待排序的关键字个数:\n");
scanf("%d", &n);
L.elem = (ElemType *) malloc ((n+1) * sizeof(ElemType));
if(!L.elem) return ERROR;
L.length = n;
printf("请输入%d个关键字:\n", n);
for(i=1; i<=n; i++)
scanf("%d", &L.elem[i]);
return OK;
}
void Load_Sq(SqList L)
{
int i;
for(i=1; i<=L.length; i++)
printf("%d ", L.elem[i]);
printf("\n");
}
插入排序
直接插入排序
直接插入排序:将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。
void InsertSort(SqList &L)
{
int i, j;
for(i=2; i<=L.length; i++)
{
if(L.elem[i] < L.elem[i-1])
{
L.elem[0] = L.elem[i];
for(j=i-1; L.elem[j]>L.elem[0]; j--)
L.elem[j+1] = L.elem[j];
L.elem[j+1] = L.elem[0];
}
Load_Sq(L);
}
}
折半插入排序
折半插入排序:在一个有序表中进行查找和插入,利用“折半查找”来实现查找。
void BInsertSort(SqList &L)
{
int low, high, mid;
int i, j;
for(i=2; i<=L.length; i++)
{
low = 1; high = i-1;
L.elem[0] = L.elem[i];
while(low<=high)
{
mid = (low + high) / 2;
if(L.elem[0] < L.elem[mid]) high = mid-1;
else low = mid+1;
}
for(j=i-1; j>=high+1; j--)
L.elem[j+1] = L.elem[j];
L.elem[high+1] = L.elem[0];
Load_Sq(L);
}
}
希尔排序
希尔排序:又称为“缩小增量排序”。现将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
注意:应使增量序列中的值没有除1之外的公因子,并且最后一个增量必须等于1。
(希尔排序是对直接插入排序改进得到的方法)
void ShellSort(SqList &L)
{
int i, j, d;
for(d=L.length/2; d>=1; d=d/2) //比直接插入排序多了最外一层循环
{
for(i=d+1; i<=L.length; i++)
{
if(L.elem[i-d] > L.elem[i])
{
L.elem[0] = L.elem[i];
for(j=i-d; j>0 && L.elem[j]>L.elem[0]; j-=d)
L.elem[j+d] = L.elem[j];
L.elem[j+d] = L.elem[0];
}
}
Load_Sq(L);
}
}
交换排序
冒泡排序
冒泡排序(起泡排序):相邻两个关键字比较
判别结束条件:在一趟排序过程中没有进行过交换记录的操作
void BubbleSort(SqList &L)
{
int i, j, flag;
ElemType temp;
for(i=1; i<L.length; i++)
{
flag = 0;
for(j=2; j<=L.length-i+1; j++)
{
if(L.elem[j-1] > L.elem[j])
{
temp = L.elem[j-1];
L.elem[j-1] = L.elem[j];
L.elem[j] = temp;
flag = 1;
}
}
Load_Sq(L);
if(flag==0) break;
}
}
快速排序
快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。
int Partition(SqList &L, int low, int high) //一趟
{
ElemType pivotkey;
L.elem[0] = L.elem[low];
pivotkey = L.elem[low];
while(low < high)
{
while(low<high && pivotkey<=L.elem[high]) high--;
L.elem[low] = L.elem[high];
while(low<high && pivotkey>=L.elem[low]) low++;
L.elem[high] = L.elem[low];
}
L.elem[low] = L.elem[0];
return low;
}
void QuickSort(SqList &L, int low, int high)
{
int pivotloc;
if(low < high)
{
pivotloc = Partition(L,low, high);
Load_Sq(L);
QuickSort(L, low, pivotloc-1);
QuickSort(L, pivotloc+1, high);
}
}
选择排序
简单选择排序
简单选择排序:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。
void SelectSort(SqList &L)
{
int i, j, min;
ElemType temp;
for(i=1; i<=L.length; i++)
{
min = i;
for(j=i+1; j<=L.length; j++)
if(L.elem[j] < L.elem[min]) min = j;
temp = L.elem[i];
L.elem[i] = L.elem[min];
L.elem[min] = temp;
Load_Sq(L);
}
}
堆排序
下面程序排序结果为“大顶堆”(非递减有序)!
先输出初始建堆后的结果;
其后各行输出交换堆顶元素并调整堆的结果。
void HeapAdjust(SqList &L, int s, int m) //s是开始比较的父母结点,m是最后一个结点的位置
{ //大顶堆
int i;
ElemType rc;
rc = L.elem[s];
for(i=2*s; i<=m; i*=2)
{
if(i<m && L.elem[i]<=L.elem[i+1]) i++;
if(rc >= L.elem[i]) break;
L.elem[s] = L.elem[i];
s = i;
}
L.elem[s] = rc;
}
void HeapSort(SqList &L)
{
int i;
ElemType temp;
for(i=L.length/2; i>0; i--)
HeapAdjust(L,i,L.length);
Load_Sq(L);
for(i=L.length; i>1; i--)
{
temp = L.elem[1];
L.elem[1] = L.elem[i];
L.elem[i] = temp;
HeapAdjust(L,1,i-1);
Load_Sq(L);
}
}
归并排序
2-路归并排序
2-路归并排序:将一位数组中前后相邻的两个有序序列归并为一个有序序列。
初始n个记录可看成n个有序子序列,前后相邻两两归并。
void Merge(SqList &L, SqList &T, int i, int m, int n) //L是表一,T是表二,i是表一起点,m是表一终点,n是表二终点 (两个表排序)
{
int j, k;
k = i; j=m+1;
while(i<=m && j<=n)
{
if(L.elem[i] <= L.elem[j])
T.elem[k++] = L.elem[i++];
else T.elem[k++] = L.elem[j++];
}
while(i<=m) T.elem[k++] = L.elem[i++];
while(j<=n) T.elem[k++] = L.elem[j++];
}
void MergeSort(SqList &L)
{
SqList T;
int start1, end1, start2, end2, i, j;
T.elem = (ElemType *) malloc ((L.length+1) * sizeof(ElemType));
T.length = L.length;
for(i=1; i<=L.length; i*=2) //找到两个表的起始位置
{
for(start1=1; start1+i-1<L.length; start1=end2+1)
{
end1 = start1+i-1;
start2 = end1+1;
end2 = start2+i-1;
if(end2 > L.length) end2 = L.length;
Merge(L, T, start1, end1, end2);
}
for(j=1; j<=L.length; j++) L.elem[j] = T.elem[j];
Load_Sq(L);
}
}
基数排序
基数排序:是和前面所述各类排序方法完全不相同的一种排序方法。前面的方法通过关键字间的比较和移动,而基数排序借助多关键字排序的思想(“分配”和“收集”)。
#include<stdio.h>
#include<string.h>
#define MAX_NUM_OF_KEY 8
#define RADIX 10
#define MAX_SPACE 10000
typedef int KeysType;
typedef struct{
KeysType keys[MAX_NUM_OF_KEY];
int next;
}SLCell;
typedef struct{
SLCell r[MAX_SPACE];
int keynum;
int recnum;
}SLList;
typedef int ArrType[RADIX];
void CreateSList(SLList & );
void PrintSList(SLList );
void Distribute(SLList & , int , ArrType & , ArrType & );
void Collect(SLList & , int , ArrType , ArrType );
void RadixSort(SLList & );
int main()
{
SLList L;
CreateSList(L);
RadixSort(L);
}
void CreateSList(SLList &L) //创建
{
int n, key, i, j, max=0;
printf("请输入待排序关键字个数:\n");
scanf("%d", &n);
printf("请输入%d个待排序关键字(用空格隔开):\n", n);
for(i=1; i<=n; i++)
{
scanf("%d", &key);
for(j=0; key!=0; j++)
{
L.r[i].keys[j] = key % 10;
key = key / 10;
}
if(j>max) max = j;
L.r[i-1].next = i;
}
L.keynum = max;
L.recnum = n;
L.r[L.recnum].next = 0;
}
void PrintSList(SLList L) //输出
{
int p, i;
for(p=L.r[0].next; p; p=L.r[p].next)
{
for(i=L.keynum-1; i>=0; i--)
printf("%d", L.r[p].keys[i]);
printf(" ");
}
printf("\n");
}
void Distribute(SLList &L, int i, ArrType &f, ArrType &e) //分配
{
KeysType j;
int p;
for(j=0; j<RADIX; j++) f[j] = 0;
for(p=L.r[0].next; p; p=L.r[p].next)
{
j = L.r[p].keys[i];
if(!f[j]) f[j] = p;
else L.r[e[j]].next = p;
e[j] = p;
}
}
void Collect(SLList &L, int i, ArrType f, ArrType e) //收集
{
int j;
int t;
for(j=0; !f[j]; j++);
L.r[0].next = f[j];
t = e[j];
for(j++; j<RADIX; j++)
if(f[j])
{
L.r[t].next = f[j];
t = e[j];
}
L.r[t].next = 0;
}
void RadixSort(SLList &L)
{
ArrType f, e;
int i;
for(i=0; i<L.keynum; i++)
{
Distribute(L, i, f, e);
Collect(L, i, f, e);
PrintSList(L);
}
}