码迷,mamicode.com
首页 > 其他好文 > 详细

排序算法及其比较--数据结构课设

时间:2014-09-10 17:38:30      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   io   使用   ar   strong   

 排序算法及其比较

课程设计报告

一、 设计内容

编程实现希尔、快速、堆排序、归并排序算法,并利用程序统计每种算法的执行时间。要求随机产生10000(或50000、 100000、 200000,由用户选择)个数据存入数据文件,然后读数据文件,分别采用不同排序方法进行排序,将结果存入另一个文件中。

 

二、 设计思想描述

1.  总思想

本程序采用模块化设计思想,分为产生随机数模块,计时模块,写入磁盘模块,读出磁盘模块,希尔排序模块,快速排序模块,堆排序模块,归并排序模块,计时模块。对常见的种经典排序算法希尔、快速、堆排序、归并排序进行实现,并根据待排数据个数的不同来对各种排序算法的执行时间进行比较,从而比较出在不同的情况下各排序算法的性能。

2.  模块介绍

【随机数模块】通过rand()函数实现,为防止每次随机数一样,用srand(time(NULL)) 设置时间种子,得到的随机数写入磁盘。

 【计时模块】计时函数使用了Windows API 函数QueryPerformanceFrequency(返回硬件支持的高精度计数器的频率。) 和QueryPerformanceCounter 用于得到高精度计时器的值)来实现毫秒级的计时功能。

【写入磁盘模块】主要通过定义ofstream outfile对象来实现。

【读出磁盘模块】主要通过定义ifstream infile对象来实现。

 【希尔排序模块】Shell排序又称缩小增量排序,属插入类排序法。它的基本思想是:先将整个待排序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行一次直接插入排序。Shell是针对普通插入排序的缺陷进行的改进。

 【快速排序模块】 快速排序是对气泡排序的一种改进。它的基本思想是:首先选一个轴值(即比较的基准),将待排序记录分割成独立的两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码均大于或等于轴值,然后分别对这两部分重复上述过程,直到整个序列有序。

【堆排序模块】堆排序是简单选择排序的一种改进,它的基本思想是:利用堆结构的特点,以一维数组来存储这个堆,将堆调整为大(小)顶堆,然后取出堆顶元素,余下的继续调整为大(小)顶堆,如此直到取出所有元素,排序完成。

 【归并排序模块】归并排序的前提是待排记录的两个子表分别有序,然后将其归并至一个有序的新表中,归并前的有序子表也是归并排序的结果。从最原始的只含一个元素的两子表,可看成有序的,经上述归并完成最终排序。

 

三、 程序结构

 【分发包说明】

 

文件名

说明

Data1.txt

存放随机生成数的文本

Data2.txt

存放已排序数的文本

main.cpp

C++源文件,包含主程序界面的实现

Operation.h

头文件,包含随机生成数、计时、读写文件等操作

Sort.h

头文件,包含四种排序算法

课设报告1

本文档

 

【主程序设计】

 

                                bubuko.com,布布扣

【流程图】

                                                     bubuko.com,布布扣

 

四、 使用说明(测试案例)

【系统环境】 

bubuko.com,布布扣

 

【使用说明】

一开始:打印使用说明

 

bubuko.com,布布扣

选择:产生随机数并存入文档,设定数据个数为10000

bubuko.com,布布扣

 选择:读取待排序数据 

bubuko.com,布布扣

选择3:排序,并计算四种算法所用的时间,以作比较

bubuko.com,布布扣

 选择:将结果存入新的文档中

bubuko.com,布布扣

 此时,到文件夹中打开Data1.txtData2.txt会看到数据。

完毕。

 

五、 排序算法比较

 

当数据分别有10000200003000050000100000个时,各个算法所用时间如下:

n = 10000

 

bubuko.com,布布扣

n = 20000

bubuko.com,布布扣

做成【折线图】为:

                                         bubuko.com,布布扣

 

 六、 设计中遇到的问题及其解决方案

 1.  const修饰变量的好处

  const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。[出自百度百科]

例如,在写入磁盘函数中:const char *file_name,告诉编译器在这个函数中,file_name不能被修改,防止我们无意的修改。

2.  精确计时函数

在定时前应该先调用QueryPerformanceFrequency()函数获得机器内部计时器的时钟频率。接着在需要严格计时的事件发生前和发生之后分别调用QueryPerformanceCounter(),利用两次获得的计数之差和时钟频率,就可以计算出事件经历的精确时间。

 附上源代码:

bubuko.com,布布扣
//main.cpp

#include <iostream>
#include <fstream>
#include <cctype>
#include <cstdlib>
#include "time.h"
#include "Sort.h"
#include "Operation.h"
using namespace std;

//声明
int Menu( );
void Control( );

int main()
{
    cout<<"                【欢迎使用本排序程序.】\n\n";
    Sleep(2000);   //停留2秒
    cout<<"【您有5秒钟的时间浏览使用说明...】\n\n";
    Sleep(1000);
    cout<<"【本程序会随机产生n个数,存入Data1.txt文件中,再从文件中读取数据,\n";
    cout<<"利用四种排序(希尔、快速、堆、归并排序)算法对待排数据排序,并将结\n";
    cout<<"果存入Data2.txt文件中。】\n";
    Sleep(5000);
    cout<<"【请根据菜单提示 按步执行...】\n";
    Sleep(1000);
    Control( );
    return 0;
}





//菜单
int Menu( )
{
    cout<<"+------------------------------+\n";
    cout<<"1...产生随机数 存入磁盘文件\n";
    cout<<"2...从文件读数据\n";
    cout<<"3...执行排序\n";
    cout<<"4...结果存入文件\n";
    cout<<"0...退出\n";
    cout<<"+------------------------------+\n";
    cout<<"Please input your choice:    ";
    int choice;
    cin>>choice;
    cout<<endl;
    return choice;

}
void Control( )
{
    //数据准备
    int *array_cin;  //待排数组
    int *array_cout; //排好序的数组
    int sort_time[4] = { 0 };  //记录给算法的用时
    int n;             //个数

    while(1)
    {
        int choice = Menu();
        if(choice == 0) break;
        switch(choice)
        {
        case 1:  
            cout<<"【请输入待排数据的个数, 例如10000, 20000, 50000....】   ";
            cin>>n;
            cout<<endl;
            array_cin = new int[n];
            array_cout = new int[n];
            GetRandom(array_cin, n);
            cout<<"【随机产生"<<n<<"个数据 OK...】\n\n";
            MyCout(array_cin, n, "Data1.txt");
            cout<<"【数据存入Data1.txt文档 OK...】\n\n";
            break;
        case 2: 
            MyCin(array_cin, n, "Data1.txt");
            cout<<"【读入数据 OK...】\n\n";
            break;
        case 3:      
            sort_time[0] = GetTime(ShellSort, array_cin, array_cout,n);
            sort_time[1] = GetTime(QuickSort, array_cin, array_cout,n);
            sort_time[2] = GetTime(HeapSort, array_cin, array_cout,n);
            sort_time[3] = GetTime(MergeSort, array_cin, array_cout,n);
            cout << "待排数据已经排序,各排序算法的执行时间已分别被记录." << endl;
            cout<<endl<<"4种排序算法的执行时间分别为:"<<endl;
            ShowTime(sort_time, 4);
            cout << endl;
            break;
        case 4:  
            MyCout(array_cout, n, "Data2.txt");
            cout << "【结果存入Data2.txt文档 OK...】\n\n";
            
            //清除数据
            //delete array_cin;
            //delete array_cout;
            cout<<endl;
            Sleep(1000);
            
            break;
        default: cout<<"【输入选择错误!!】\n";
            Sleep(10000);
        }//switch
    }//while
}//Control


//Operation.h  操作函数:读文件 写文件 产生随机数 精确计时 等

#include <windows.h>
#include <iostream>
#include <fstream>
#include "time.h"
using namespace std;



//************************产生随机数*****************************
void GetRandom(int *data, const int n)
{
    srand(time(NULL));              //随机生成n个随机数
    for(int i=1; i<=n; i++)
        data[i] = rand();
}


//************************写文件*********************************
void MyCout(int *data, int n, const char *file_name)
{
    fstream fout;
    fout.open(file_name,ios::out);
    if(fout.is_open())
    {
        fout<<"*********\n";
        fout<<"*********\n";
        for(int i=1;i<=n;i++)
        {
            fout<<data[i]<<"  ";
            if(i%10 == 0)
                fout<<\n; 
        }//for
    }//if
    fout<<endl;
    fout.close();
}

//************************读文件**********************************
void MyCin(int data[], int n, const char *file_name)
{
    fstream fin;
    fin.open(file_name,ios::in);    
    if(fin.is_open())
    {
        for(int i=1;i<=n;i++)
        {
            fin>>data[i];
        }
    }
    fin.close();
}

//**************************精确计时******************************8
int GetTime(void (*fpt)(const int *array_to_sort, int *sorted_array, const int n),
            const int *array_to_sort, int *sorted_array, const int n) 
{
    LARGE_INTEGER iLarge;
    //获得频率
    QueryPerformanceFrequency( &iLarge );
    double dbFreq = (double) iLarge.QuadPart;
    //获得开始时间
    QueryPerformanceCounter( &iLarge );
    double dbBegin = (double) iLarge.QuadPart;
    //执行排序算法
    fpt(array_to_sort, sorted_array, n);
    //获得结束时间
    QueryPerformanceCounter( &iLarge );
    double dbEnd = (double) iLarge.QuadPart;
    //计算用时
    int nms = (int) (( dbEnd - dbBegin ) * 1000.0 / dbFreq );
    return nms;
}

//**************************打印时间***************************************
void ShowTime(int array_to_show[], const int n) 
{
    char *name[4] = { "Shell Sort", "Quick Sort", "Heap Sort", "Merge Sort"};
    //显示时间
    for (int i = 0; i < n; i++) 
    {
        cout <<""<<name[i] << ":" << array_to_show[i] << " ms 】"<<endl;        
    }
}

//Sort.h  排序函数:希尔排序 快速排序 堆排序 归并排序

#include <iostream>
using namespace std;


//*****************希尔排序***********************
void shellsort(int data[], int n)
{
    for(int d=n/2,c=1; d>=1; d=d/2,c++)     //以增量为d进行直接插入排序
    {
        for(int i=d+1; i<=n; i++)
        {
            data[0] = data[i];                //暂存被插入记录
            for(int j=i-d; j>0&&data[0]<data[j]; j=j-d)
                data[j+d] = data[j];        //记录后移d个位置
            data[j+d] = data[0];
        }
    }
    
}
//**主调函数**
void ShellSort(const int *array_to_sort, int *sorted_array, const int n) 
{
    for (int i = 0; i < n; i++) 
        sorted_array[i] = array_to_sort[i];
    shellsort(sorted_array, n);
}



//*****************快速排序***********************
int Partition(int data[], int first, int end)
{
    int i = first, j = end;    //初始化
    while(i<j)
    {
        while(i<j && data[i]<=data[j]) j--;  //右侧扫描
        if(i<j)   //将较小记录交换到前面
        {
            int temp = data[i];
            data[i] = data[j];
            data[j] = temp;
            i++;
        }
        while(i<j && data[i]<=data[j]) i++;  //左侧扫描
        if(i<j)   //将较大记录交换到后面
        {
            int temp = data[i];
            data[i] = data[j];
            data[j] = temp;
            j--;
        }
    }//while
    return i;   //i为轴值记录的最终位置
}
void quicksort(int data[], int first, int end)
{
    int c=0;
    if(first < end)
    {
        int pivot = Partition(data,first,end);
        quicksort(data,first,pivot-1);  //递归地对左侧子序列进行快速排序
        quicksort(data,pivot+1,end);    //递归地对右侧子序列进行快速排序
        c++;
    }
    
}
//**主调函数**
void QuickSort(const int *array_to_sort, int *sorted_array, const int n) 
{
    for (int i = 0; i < n; i++)
        sorted_array[i] = array_to_sort[i];
    quicksort(sorted_array, 0, n);
}


//*****************堆排序***********************
void Sift(int data[], int k, int m)
{
    int i=k;   //置i为要筛的结点,j为i的左孩子
    int j = i*2;
    while(j<=m)   //筛选还没有进行到叶子
    {
        if(j<m && data[j]<data[j+1]) j++;
        if(data[i]>data[j]) break;
        else
        {
            int temp = data[i];
            data[i] = data[j];
            data[j] = temp;
            i = j;
            j = 2*i;
        }//else
    }//while
}

void heapsort(int data[], int n)
{
    //初建堆,从最后一个非终端结点至根结点
    for(int i=n/2; i>=1; i--)
        Sift(data,i,n);
    //调整,重复执行移走堆顶及重建堆的操作
    for(i=1; i<n; i++)  
    {
        int temp = data[1];
        data[1] = data[n-i+1];
        data[n-i+1] = temp;
        Sift(data,1,n-i);
    }
}

//**主调函数**
void HeapSort(const int *array_to_sort, int *sorted_array, const int n) 
{
    for (int i = 0; i < n; i++)
        sorted_array[i] = array_to_sort[i];
    heapsort(sorted_array, n);
}


//*****************归并排序***********************
//一次归并算法
void Merge(int r[], int r1[], int s, int m, int t)
{
    int i = s, j = m+1, k = s;
    while(i<=m && j<=t)
    {
        if(r[i]<=r[j]) r1[k++] = r[i++];  //取r[i]和r[j]中较小者放入r1[k]
        else r1[k++] = r[j++];
    }//while
    if(i<=m)while(i<=m)  //若第一个子序列没处理完,则进行收尾处理
        r1[k++] = r[i++];
    else while(j<=t)     //若第二个子序列没处理完,则进行收尾处理        
        r1[k++] = r[j++];
}
//一趟归并算法
void MergePass(int r[], int r1[], int n, int h)
{
    int i=1;
    while(i<=n-2*h+1)   //待归并记录至少有两个长度为h的子序列
    {
        Merge(r,r1,i,i+h-1,i+2*h-1);
        i+=2*h;
    }//while
    if(i<n-h+1) Merge(r,r1,i,i+h-1,n);  //待归并序列中有一个长度小于h
    else for(int k=i; k<=n; k++)        //待归并序列中只剩一个子序列
        r1[k] = r[k];
}
//归并排序非递归
void MergeSort1(int r[], int r1[], int n)
{
    int h=1;
    while(h<n)
    {
        MergePass(r,r1,n,h);
        h = 2*h;
        MergePass(r1,r,n,h);
        h = 2*h;
    }//while
}
//**主调函数**
void MergeSort(const int *array_to_sort, int *sorted_array, const int n) 
{
    int sorted_array1[200000]={0};  //数组要大!
    for (int i = 0; i < n; i++) 
        sorted_array[i] = array_to_sort[i];
    MergeSort1(sorted_array, sorted_array1,n);
}
View Code

 

 

 

排序算法及其比较--数据结构课设

标签:style   blog   http   color   os   io   使用   ar   strong   

原文地址:http://www.cnblogs.com/daben/p/3964652.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!