建立含有若干个整数的顺序表,在此基础上实现顺序表的各种排序算法
)
顺序表的排序实验
实验目的
掌握以顺序表组织待排序数据元素的排序方法,尤其是希尔排序、快速排序
实验背景
排序是将一组具有相同数据类型的数据元素调整为按关键字从小到大(或从大到小)排列的过程。
为方便算法的实现,我们将组织待排元素的顺序表的数据类型定义如下:
#define MAXSIZE 20
typedef struct
{
int r[MAXSIZE + 1]; // r[0]为工作单元或闲置
int length; // length为顺序表的长度
} SqeList; //顺序表类型
1、直接插入排序
直接插入排序的基本思想是:将整个数据表分成左右两个子表;其中左子右子表为无序表;整个排序的过程就是将右子表中的元素逐个插入到左子表中为空,而左子表成为新的有序表。
算法描述如下:
void *InsertSort(SqeList *L){ //对顺序表L中的元素做直接插入
int j,i;
for (i = 1; i <= L->length; i++){
L->r[0] = L->r[i];
j = i - 1; //将待插入元素存到监视哨r[0]中}
while (L->r[0] < L->r[j]){ //寻找插入位置
L->r[j + 1] = L->r[j];
j = j - 1;
}
L->r[j + 1] = L->r[0]; //将待插入元素插入到已排序的序列中
}}
2、希尔排序
基本思想:先将整个待排序元素序列分割成若干子序列,对每个子序列分别插入排序,当整个待排序元素序列"基本有序"时,再对全体元素进行一次直接插入
将待排序元素序列调整为基本有序的方法是:选择一个步长值d ,将元素的倍数的元素放在一组(子序列),在每组内作直接插入排序。
算法描述如下:
void Shelllnsert(SqeList *L, int di){//对顺序表L做一趟希尔插入排序,di为该趟排序的增量
int i,j;
for (i = 1 + di; i <= L->length; i++) // 1+di为第一个子序列的第二个元
if (L->r[i] < L->r[i - di]){
L->r[0]= L->r[i];//备份L->r[i](不做监视哨)
for (j = i - di; (j > 0) && (L->r[0] < L->r[j]); j -= di) L->r[j + di] = L->r[j];
L->r[j + di] = L->r[0];
}
read(L);
}
void ShellSort(SqeList *L,int delta[],int n)
{//对顺序表L按增量序列delta[0] ~ delta[n-1]做希尔排序
int i;
for (i = 0; i <= n - 1; i++)
Shelllnsert(L,delta[i]);
}
3、冒泡排序
基本思想是:两两比较待排序元素的关键字,发现它们次序相反时即进行有逆序的元素为止。
冒泡排序算法如下:
void BubbleSort(SqeList *L){//对顺序表L做冒泡排序
int i,j,n,change;
int x;
n = L->length;
change = 1; //change为记录元素交换
for (i = 0; i < n && change; ++i){ //做n-1趟排序
change = 0;
for (j = 0; j < n - i; ++j)
if (L->r[j] > L->r[j + 1]){
x = L->r[j];
L->r[j] = L->r[j + 1];
L->r[j + 1] = x;
change = 1;
}}}
4.快速排序
基本思想:在待排序元素中选定一个作为"中间数”,使该数据表中的其他与“中间数"的关键字比较,将整个数据表划分为左右两个子表,其中左边子表键字不大于右边子表中任一元素的关键字;然后再对左右两个子表分别进行快整个数据表有序。
这里,我们选取数据表中的第一个数为"中间数”。快速排序一次划分的算法描述为:
int Partition(SqeList *H,int left,int right)
{//对顺序表H中的H->r[left]至H->r[right]部分进行快速排序的一次划分,放中间数的位置(基准位置)
int x;
int low, high;
x = H->r[left];// 选择中间数
low = left;high = right;
while (low < high){
while (H->r[high] >= x && low < high) high--;
//首先从右向左扫描,查找第一个关键字小于x.key的元素
if (low < high){
H->r[low] = H->r[high];low++;
}
while (H->r[low] < x && low < high) low++;
//然后从左向右扫描,查找第一个关键字不小于x.key 的元素
if ( low<high){
H->r[high] = H->r[low]; high--;
}
}
H->r[low] = x;
//将中间数保存到 low=high 的位置
return low;//返回存放中间数的位置
}
对整个数据表进行快速排序,是在一次划分后,对左右子表分别进行快速整个排序过程是一个递归形式的算法。算法描述如下:
void QuickSort(SqeList *L,int low,int high)
{ //对顺序表L用快速排序算法进行排序
int mid;
if (low < high)
{
mid = Partition(L,low,high);
QuickSort(L,low,mid - 1);
QuickSort(L,mid + 1, high);
}
}
5、直接选择排序
直接选择排序的基本思想是:在第i趟直接选择排序中,通过n-i次关键n-i+1个元素中选出关键字最小的元素,与第i个元素进行交换。经过n-1趟比据表有序为止。
直接选择排序的算法可以描述为:
void SelectSort(SqeList *L){//对顺序表L做直接选择排序
int n,i;
n = L->length;
for (i = 0; i < n - 1; ++i){
k = i;
for (j = i + 1; j < n; ++j)
if (L->ri]<L->r[k])k=j;
if (k ! = i)
{
x = L->rli;
L->rli = L->r[k];
L->r[k] = x;
}
}
}
6.归并排序
最基本的归并是将两个有序表合并成一个有序表:
若有序表A,B同属于一个数据表R,是R的两个有序区,并且R[low]~R[mid]为有序表A的存储区,R[mid+1]~R[high]为有序表B的存储区。将其归并为一个放在数组R1中。
其算法描述如下:
void Merge(RecordType R,RecordType R10,int low,int mid,int high){
//数组R中R[low]~R[mid]和R[mid+1]~R[high]分别按关键字有序排列,
//将它们合并成一个有序序列,存放在数组R1的R1[low]~R1[high]中
int i, j,k;
i = low;j = mid + 1;k = low;
while (i <= mid && j <= high){
if (R[i] <= R[i]){
R1[k] = R[i];++i;}
else{
R1[k]= R[i];++j;}
++k;
}
while (i <= mid) R1[k++]=R[i++];
while (j <= mid) R1[k++]=R[j++];
}
归并排序是利用上述归并技术来进行排序的。其基本思想是,将长度为n表看成是n个长度为1的有序表,将这些有序表两两归并,便得到[n /2]个有这[n /2]个有序表两两归并,如此反复,直到最后得到长度为n的有序表为止
这样,每次归并操作都是将两个有序表合并成一个有序表,我们称这种方并排序。
2路归并的一趟归并算法描述为:
void Mergepass(RecordType R,RecordType R10,int len){
// 对R作一趟归并, 结果放在R1中
int j,i = 0;
while (i + len * 2 <= n){// i + len * 2 - 1 > n - 1时不再排序
Merge(R,R1,i,i + len - 1,i + len * 2 - 1);
i = i + len * 2;
}
if (i + len - 1 < n - 1) Merge(R,R1,i,i + len - 1, n - 1);
else
for (j=i; j<n; j++)
R1[i] = Rli];
}
对无序表进行2路归并排序就是调用上述一趟归并算法,对待排序序列迂并。第一趟归并时,每个有序表的长度为1,即len=1。归并后有序表的长度倍,即排序中len从1,2,4…到[n /2],可以用while循环实现整个归并过过程
MergeSort(SqeList L){
//对顺序表L中的待排序序列进行归并排序结果仍在顺序表L中
int len, n;
int *R1;
n = L.length; len = 1;
R1 = (int *)malloc(sizeof(int) * n);
while (len <= n / 2 + 1){
Mergepass(L.r,R1,len);
// 一趟归并,结果在R1中
len = 2 * len;
Mergepass(R1,L.r,len);
// 再次归并,结果在R中
len = 2 * len;
}
free(R1);
}
建立含有若干个整数的顺序表,在此基础上实现顺序表的各种排序算法。包括:直接插入排序、希尔排序、冒泡排序、快速排序和直接选择排序
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
typedef struct
{
int r[MAXSIZE + 1]; // r[0]为工作单元或闲置
int length; // length为顺序表的长度
} SqeList;
SqeList *S_null(SqeList *L){
L=(SqeList *)malloc(sizeof(SqeList));
L->length=0;
return L;
}
SqeList *S_c(SqeList *L){
L=S_null(L);
int n;
printf("'0'退出");
scanf("%d",&n);
while(n!=0){
if(L->length==MAXSIZE){
printf("已满");
break;
}
L->length++;
L->r[L->length]=n;
scanf("%d",&n);
}
return L;
}
void read(SqeList *L){
int i=0;
for ( i = 1; i <= L->length; i++)
printf("%d ",L->r[i]);
printf("\n");
}
void *InsertSort(SqeList *L)
{ //对顺序表L中的元素做直接插入
int j,i;
for (i = 1; i <= L->length; i++)
{
L->r[0] = L->r[i];
j = i - 1; //将待插入元素存到监视哨r[0]中}
while (L->r[0] < L->r[j])
{ //寻找插入位置
L->r[j + 1] = L->r[j];
j = j - 1;
}
L->r[j + 1] = L->r[0]; //将待插入元素插入到已排序的序列中
}
}
void Shelllnsert(SqeList *L, int di)
{//对顺序表L做一趟希尔插入排序,di为该趟排序的增量
int i,j;
for (i = 1 + di; i <= L->length; i++) // 1+di为第一个子序列的第二个元
if (L->r[i] < L->r[i - di])
{
L->r[0]= L->r[i];//备份L->r[i](不做监视哨)
for (j = i - di; (j > 0) && (L->r[0] < L->r[j]); j -= di)
L->r[j + di] = L->r[j];
L->r[j + di] = L->r[0];
}
read(L);
}
void ShellSort(SqeList *L,int delta[],int n)
{//对顺序表L按增量序列delta[0] ~ delta[n-1]做希尔排序
int i;
for (i = 0; i <= n - 1; i++)
Shelllnsert(L,delta[i]);
}
void BubbleSort(SqeList *L)
{
//对顺序表L做冒泡排序
int i,j,n,change;
int x;
n = L->length;
change = 1; //change为记录元素交换
for (i = 0; i < n && change; ++i)
{ //做n-1趟排序
change = 0;
for (j = 0; j < n - i; ++j)
if (L->r[j] > L->r[j + 1])
{
x = L->r[j];
L->r[j] = L->r[j + 1];
L->r[j + 1] = x;
change = 1;
}
}
}
int Partition(SqeList *H,int left,int right)
{//对顺序表H中的H->r[left]至H->r[right]部分进行快速排序的一次划分,放中间数的位置(基准位置)
int x;
int low, high;
x = H->r[left];// 选择中间数
low = left;high = right;
while (low < high){
while (H->r[high] >= x && low < high) high--;//首先从右向左扫描,查找第一个关键字小于x.key的元素
if (low < high){
H->r[low] = H->r[high];low++;
}
while (H->r[low] < x && low < high) low++;//然后从左向右扫描,查找第一个关键字不小于x.key 的元素
if ( low<high){
H->r[high] = H->r[low]; high--;
}
}
H->r[low] = x; //将中间数保存到 low=high 的位置
return low;//返回存放中间数的位置
}
void QuickSort(SqeList *L,int low,int high)
{ //对顺序表L用快速排序算法进行排序
int mid;
if (low < high)
{
mid = Partition(L,low,high);
QuickSort(L,low,mid - 1);
QuickSort(L,mid + 1,high);
}
}
void SelectSort(SqeList *L){//对顺序表L做直接选择排序
int n,i,k,j,x;
n = L->length;
for (i = 0; i < n; ++i){
k = i;
for (j = i + 1; j <= n; ++j)
if (L->r[j]<L->r[k])k=j;
if (k!=i)
{
x = L->r[i];
L->r[i]= L->r[k];
L->r[k] = x;
}
}
}
int main(void){
SqeList *L;
int d[]={5,2,1};
L=S_c(L);
read(L);
//InsertSort(L);//直接插入
//ShellSort(L,d,3);//希尔排序
//BubbleSort(L);//冒泡排序
//QuickSort(L,1,L->length);//快速排序
//SelectSort(L);//直接选择排序
read(L);
return 0;
}