數據結構各種排序的實驗


數據結構與算法實驗報告

第五次實驗

  姓名:孫瑞霜 

 

一、實驗目的

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