数据结构各种排序的实验


数据结构与算法实验报告

第五次实验

  姓名:孙瑞霜 

 

一、实验目的

1、复习各种排序方法的算法思想; 

2、掌握对存储在数组中的多个元素排序的方法;

3、比较各种排序方法的效率高低。

二、实验要求

1. 认真阅读和掌握教材上和本实验相关内容和算法(P265~P283);

2. 上机将排序的各种相关算法实现;

3实现上面实验目的要求的功能,并能进行简单的验证

、实验内容

编程实现排序的所有算法,放入sort.c中,并在main函数中分别调用,实现对数组中存储的多个无序数据排序,要求能够进行简单的输入输出验证,并分析各自排序算法的效率高低(可以加大待排数据规模或者重复操作多次,参照P4~P7

#include<stdio.h>

#include<time.h>

typedef int ElementType; //元素类型为int

#include"sort.c" //把排序算法sort.c包含到当前文件

#define N 100000 //预定义N为10,表示数组中元素个数,可调

 

void Init(ElementType A[],int n)

{//对A数组中的n个元素分别赋随机值

int i;

for(i=0;i<n;i++)

A[i]=rand()%n;

}

void Print(ElementType A[],int n)

{//输出a数组中的n个元素

int i;

for(i=0;i<n;i++)

printf("%6d",A[i]);

putchar('\n');

}

int main(void)

{

ElementType A[N];

clock_t startclock,endclock; //定义时钟打点类型的两个变量

 

Init(A,N); //初始化数组

printf("排序前:\n");

Print(A,N); //输出数组

startclock=clock(); //排序前获得一个时钟打点

/*调用排序算法对A数组中的N个数排序*/

// SelectSort(A,N); //选择排序 ,可换为其他排序方法

HeapSort(A,N); //堆排序

endclock=clock(); //排序后获得一个时钟打点

printf("排序后:\n");

Print(A,N);

printf("共耗时%.3f秒\n",(double)(endclock-startclock)/CLK_TCK); //计算运行耗时

/*  CLK_TCK是机器时钟每秒所走的时钟打点数   */

return 0;

}

三、算法描述

 

第七章我们学习了选择排序、堆排序、简单插入排序、希尔排序、冒泡排序、快速排序、归并排序、基数排序8种不同的内部排序方法,它们在时间复杂度、空间复杂度和稳定性上各有优劣。不存在绝对意义上最佳的排序方法,8种排序方法分别适用于不同的条件下。例如基数排序是时间复杂度最低的排序方法,借助O(N+R)(R为每个关键字不同取值的个数)浦助空间和严格限制的元素数据类型,仅仅需要O(D(N+R))的时间复杂度。基数字适用于处理数量大、关键字取值范围有限的序列,例如扑克牌排序等。同时,基数排序也是稳定的排序方法。其余7种排序方法都是建立在比较和交换操作上的,决定其性能的是比较、交换的次数和是否需要额外空间用于保存临时值。选择排序、堆排序、希尔排序、快速排序不稳定;简单插入排序、冒泡排序、归并排序稳定。此次实验就各种排序过程及耗时进行研究。

四、详细设计

 

 

五、程序代码

#include<stdio.h>

#include<time.h>

typedef int ElementType; //元素类型为int

#include"sort.c" //把排序算法sort.c包含到当前文件

#define N 100000 //预定义N10,表示数组中元素个数,可调

 

void Init(ElementType A[],int n)

{//A数组中的n个元素分别赋随机值

int i;

for(i=0;i<n;i++)

scanf("%d",&A[i]);

}

void Print(ElementType A[],int n)

{//输出a数组中的n个元素

int i;

for(i=0;i<n;i++)

printf("%6d",A[i]);

putchar('\n');

}

int main(void)

{

int n,i;

ElementType A[N];

clock_t startclock,endclock; //定义时钟打点类型的两个变量

printf("输入要排序的个数:");

scanf("%d",&n);

Init(A,n); //初始化数组

printf("排序前:\n");

Print(A,n);

printf("\n"); //输出数组

startclock=clock(); //排序前获得一个时钟打点

/*调用排序算法对A数组中的N个数排序*/

for(i=0;i<10000000;i++)

HeapSort(A,n); //堆排序

endclock=clock(); //排序后获得一个时钟打点

printf("堆排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000; //计算运行耗时

/*  CLK_TCK是机器时钟每秒所走的时钟打点数   */

 

startclock=clock();

for(i=0;i<10000000;i++)

SimpleSelectionSort(A,n);

endclock=clock();

printf("简单选择排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

InsertionSort(A,n);

endclock=clock();

printf("插入排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

BubbleSort(A,n);

endclock=clock();

printf("冒泡排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

ShellSort(A,n);

endclock=clock();

printf("希尔排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

QuickSort(A,n);

endclock=clock();

printf("快速排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

MergeSort(A,n);

endclock=clock();

printf("归并排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

startclock=clock();

for(i=0;i<10000000;i++)

LSDRadixSort(A,n);

endclock=clock();

printf("基数排序后:\n");

Print(A,n);

printf("共耗时%.3f\n\n",(double)(endclock-startclock)/CLK_TCK)/10000000;

 

return 0;

}

 

sort.c文件

#include<stdio.h>

#include<stdbool.h>

#include<stdlib.h>

typedef int ElementType;

//简单选择排序

void swap(ElementType *a ,ElementType *b)

{

ElementType t=*a;

*a=*b;

*b=t;

}

void SimpleSelectionSort(ElementType A[], int N)

{ //简单选择排序

int i,j,min;

for(i=0;i<N-1;i++){

min=i;

for(j=i+1;j<N;j++){

if(A[j]<A[min])

min=j;//min记录最小元素位置

}

//将第i个元素与最小元素交换

swap(&A[i],&A[min]);

}

}

void PercDown(ElementType A[],int p,int N)

{ //N个元素的数组中以A[p]为跟的子堆调整为最大堆

int parent,child;

ElementType x;

x=A[p];   //取出根结点存放的值

for(parent=p;(parent*2+1)<N;parent=child){

child=parent*2+1;

if((child!=N-1)&&(A[child]<A[child+1]))

child++;   //child指向左右子结点的较大者

if(x>=A[child])   //找到了合适位置

break;

else   //下滤x

A[parent]=A[child];

}

A[parent]=x;

}

void HeapSort(ElementType A[],int N)

{ //堆排序

int i;

for(i=N/2-1;i>=0;i--)/* 建立最大堆 */

        PercDown(A,i,N);

 

for(i=N-1;i>0;i--){

        /* 删除最大堆顶 */

        swap(&A[0],&A[i]);

        PercDown(A,0,i);

    }

}

void InsertionSort(ElementType A[],int N)

{ //插入排序

int p,i;

ElementType tmp;

for(p=1;p<N;p++){

tmp=A[p];    //取出未排序序列中的第一元素

for(i=p;i>0&&A[i-1]>tmp;i--)

A[i]=A[i-1];   //依次与已排序序列中元素比较并右移

A[i]=tmp;   //放进合适的位置

}

}

void ShellSort(ElementType A[], int N)

{

int P,D,i,Si;

ElementType Tmp;

//这里只列出一小部分增量

int Sedgewick[] = {929,505,209,109,41,19,5,1, 0};

 

for(Si=0;Sedgewick[Si]>=N;Si++ )

; /* 初始的增量Sedgewick[Si]不能超过待排序列长度 */

for(D=Sedgewick[Si];D>0;D=Sedgewick[++Si]){

for(P=D;P<N;P++){

Tmp=A[P];

for(i=P;i>=D&&A[i-D]>Tmp;i-=D){

A[i]=A[i-D];

}

A[i]=Tmp;

}

}

}

void BubbleSort(ElementType A[],int N)

{ //冒泡排序

int p,i;

bool flag;

for(p=N-1;p>=0;p--){

flag=false;   //标识该次循环中是否发生交换,若无,则说明整个序列有序

for(i=0;i<p;i++){   //一趟冒泡

//每次循环找出一个最大元素,被交换到最右端

if(A[i]>A[i+1]){

swap(&A[i],&A[i+1]);

flag=true;   //标识发生了交换

}

}

if(flag==false)

break;   //若全程无交换,则跳出循环

}

}

 

ElementType Median3(ElementType A[],int Left,int Right)

{  

int Center=(Left+Right)/2;

    if(A[Left]>A[Center])

     swap(&A[Left],&A[Center]);

    if(A[Left]>A[Right])

     swap(&A[Left],&A[Right]);

    if(A[Center]>A[Right])

        swap(&A[Center],&A[Right]);

    //此时A[Left]<=A[Center]<=A[Right]

    swap(&A[Center],&A[Right-1]);    //将基准pivot藏到右边

    //只需要考虑A[Left+1]...A[Right-2]

    return A[Right-1];    //返回基准pivot

}

 

void Qsort(ElementType A[],int Left,int Right)

{//核心递归函数

int pivot,Low,High;

 

if(Left<Right){   

pivot=Median3(A,Left,Right);   //选基准

Low=Left; High=Right-1;

while(Low<High){    //将序列中比基准小的移到基准左边,大的移到右边

     while(A[++Low]<pivot);

     while(A[--High]>pivot);

        if(Low<High)

         swap(&A[Low],&A[High]);

        else

break;

}

swap(&A[Low],&A[Right-1]);   //将基准移到正确的位置

    Qsort(A,Left,Low-1);    //递归解决左边

Qsort(A,Low+1,Right);    //递归解决右边  

}

}

void QuickSort(ElementType A[],int N)

{//统一接口

    Qsort(A,0,N-1);

}

 

//L=左边起始位置,R=右边起始位置,RightEnd=右边终点位置

void Merge(ElementType A[], ElementType TmpA[],int L,int R,int RightEnd)

{//将有序的A[L]~A[R-1]A[R]~A[RightEnd]归并成一个有序序列

int LeftEnd,NumElements,Tmp,i;

LeftEnd=R-1;      //左边终点位置

Tmp=L;            //有序序列的起始位置

NumElements=RightEnd-L+1;

 

while(L<=LeftEnd&&R<=RightEnd)  

{

if(A[L]>A[R])

TmpA[Tmp++]=A[R++];   //将左边元素复制到TmpA

else

TmpA[Tmp++]=A[L++];   //将右边元素复制到TmpA

}

while(L<=LeftEnd)    

TmpA[Tmp++]=A[L++];     //直接复制左边剩下的

while(R<=RightEnd)    

TmpA[Tmp++]=A[R++];    //直接复制右边剩下的

for(i=0;i<=NumElements;i++,RightEnd--)

A[RightEnd]=TmpA[RightEnd];   //将有序的TmpA[]复制回A[]

}

void MSort(ElementType A[], ElementType TmpA[], int L, int RightEnd)  

{//核心递归排序函数

int center;

if(L<RightEnd){

center=(L+RightEnd)/2;

MSort(A,TmpA,L,center);             //递归解决左边

MSort(A,TmpA,center+1,RightEnd);    //递归解决右边

Merge(A,TmpA,L,center+1,RightEnd);  //合并两段有序序列

}

}

void MergeSort(ElementType A[],int N)

{/*归并排序 */

ElementType *TmpA;

TmpA=(ElementType *)malloc(N*sizeof(ElementType));

 

if (TmpA!=NULL)

{

MSort(A,TmpA,0,N-1);

free(TmpA);

}

else

printf("空间不足");

}

 

//假设元素最多有MaxDigit个关键字,基数全是同样的Radix

#define MaxDigit 4

#define Radix 10

 

//桶元素结点

typedef struct Node *PtrToNode;

struct Node {

int key;

PtrToNode next;

};

 

//桶头结点

struct HeadNode {

PtrToNode head,tail;

};

typedef struct HeadNode Bucket[Radix];

 

int GetDigit(int X,int D)

{//默认次位D=1,主位D<=MaxDigit

int d,i;

for(i=1;i<=D;i++){

d=X%Radix;

X/=Radix;

}

return d;

}

void LSDRadixSort(ElementType A[], int N)

{//基数排序 - 次位优先

int D,Di,i;

Bucket B;

PtrToNode tmp,p,List=NULL;

 

for(i=0;i<Radix;i++) //初始化每个桶为空链表

B[i].head=B[i].tail=NULL;

for(i=0;i<N;i++){ //将原始序列逆序存入初始链表List

tmp=(PtrToNode)malloc(sizeof(struct Node));

tmp->key=A[i];

tmp->next=List;

List=tmp;

}

//下面开始排序

for(D=1;D<=MaxDigit;D++){//对数据的每一位循环处理

//下面是分配的过程

p=List;

while(p){

Di=GetDigit(p->key,D); //获得当前元素的当前位数字

//List中摘除

tmp=p; p=p->next;

//插入B[Di]号桶尾

tmp->next=NULL;

if(B[Di].head==NULL)

B[Di].head=B[Di].tail=tmp;

else{

B[Di].tail->next=tmp;

B[Di].tail=tmp;

}

}

//下面是收集的过程

List=NULL;

for(Di=Radix-1;Di>=0;Di--){//将每个桶的元素顺序收集入List,

if (B[Di].head){//如果桶不为空

//整桶插入List表头

B[Di].tail->next=List;

List=B[Di].head;

B[Di].head=B[Di].tail=NULL;   //清空桶

}

}

}

//List倒入A[]并释放空间

for (i = 0; i<N; i++){

tmp=List;

List=List->next;

A[i]=tmp->key;

free(tmp);

}

}

 

六、测试和结果

 

 

 

七、用户手册

打开devC++,新建一个源程序,拷贝5部分的代码进去,点击运行,在出现的界面中按照提示输入数据一步步按下回车键即可运行该程序,最后测试完毕,关闭界面

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM