DATASIZE为数据量,可自行更改
自动生成数据无需文件导入
能随机生成DATASIZE个数据保存在文件data.txt文件中。
八大排序将排序结果保存在result.txt文件
花费时间 比较次数 稳定性检测 在文件 time.txt中
完整代码
#include <iostream>
#include <fstream>
#include <ctime>
#include <stdlib.h> using namespace std;const int DATASIZE = 20000; //数据量 typedef struct Node{
int num;int count;
}Data;typedef struct LNode{
//变成一个结构体变量这样传参数的时候就不会因为是数组而改变数组值了 Data data[DATASIZE + 1];int length;
}List;
List L,S; //记录未排序数据 long long int compare[8]; /*插入0希尔1冒泡2 快排3 选择4 堆5 归并6 分别进行了几次比较*/ long long dt[32];
clock_t start, stop; /*clock_t是clock()函数返回的变量类型*/
double duration; /*记录\n时间,单位秒*/ ofstream Record; //记录 排序结果 比较次数 稳定性 \n时间花费
ofstream Timecost;void getdt(void){
//计算希尔排序的增量 2^n - 1 保存在数组dt中 int index = 0;long long key = 2; while(index < 32){
dt[index] = key-1;key<<1;index++;}return;
}void CreateData(void){
//随机生成数据 ofstream out;out.open("data.txt");for(int i = 0;i < DATASIZE;i++){
out << rand()%100000 << "\t";}out.close();return;
}void ReadData(void){
//从文件读取数据 ifstream in;in.open("data.txt");int index = 1,j;while(in >> L.data[index].num){
L.data[index].count = 1; //假设第一次出现为1 j = index-1;while(j && L.data[index].num != L.data[j].num){
//先前找看是否有相同的数 j--; }if(j) //如果已经出现过这个数 L.data[index].count = L.data[j].count + 1;index++;}in.close();return;
}bool stability(List Ltemp){
int index = 1;while(index <= Ltemp.length-1){
if((Ltemp.data[index].num == Ltemp.data[index+1].num) && (Ltemp.data[index].count > Ltemp.data[index+1].count)){
//关键字相同 乱序 return false;}index++;}return true;
} void InsertSort(List Ltemp){
//直接插入插入排序 int j = 0;start = clock();for(int i = 2;i <= Ltemp.length;++i){
compare[0]++; //记录比较次数 if(Ltemp.data[i].num < Ltemp.data[i-1].num){
//如果比前面的已经有序的数小,那么就进行插入排序 Ltemp.data[0] = Ltemp.data[i];Ltemp.data[i] = Ltemp.data[i-1]; //前面大的数后移for(j = i - 2;Ltemp.data[0].num < Ltemp.data[j].num;--j){
compare[0]++;Ltemp.data[j+1] = Ltemp.data[j];} Ltemp.data[j+1] = Ltemp.data[0]; //找到位置后插入 }}stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "直接插入排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "直接插入排序\n时间: " << duration << "\t比较次数: " << compare[0] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;}void ShellInsert(List &Ltemp,int dk){
//希尔排序 int j;for(int i = dk + 1;i <= Ltemp.length;++i){
//i-dk>0 compare[1]++; //记录比较次数 if(Ltemp.data[i].num < Ltemp.data[i-dk].num){
//增量为dk的直接插入排序 Ltemp.data[0] = Ltemp.data[i];for(j = i - dk;(j >0) && ( Ltemp.data[0].num < Ltemp.data[j].num);j-=dk){
Ltemp.data[j+dk] = Ltemp.data[j];compare[1]++; } Ltemp.data[j+dk] = Ltemp.data[0]; }}return ;
}void ShellSort(List Ltemp,long long dt[]){
//希尔排序 int index = 0;start = clock();while(dt[index] * 2 <= DATASIZE){
//找到合适的增量起始位置 index++;}for(int i = index;i >= 0;--i){
ShellInsert(Ltemp,dt[i]); //根据不同的增量进行插入排序 } stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "希尔排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" <<endl;Timecost << "希尔排序\n时间: " << duration << "\t比较次数: " << compare[1] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl; else Timecost << "\t不稳定\n" << endl;return ;
}void BubbleSort(List Ltemp){
//冒泡排序 int j,m,flag;Data t; //用于交换 m = Ltemp.length -1;flag = 1;start = clock(); while((m >0) && flag){
//flag是否已经有序 compare[2]++;flag = 0;for(j = 1;j <= m;j++){
compare[2]++; //记录比较次数 if(Ltemp.data[j].num > Ltemp.data[j+1].num){
//如果逆序则交换 flag = 1;t = Ltemp.data[j];Ltemp.data[j] = Ltemp.data[j+1];Ltemp.data[j+1] = t; }}--m; //扩大有序范围 }stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "冒泡排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "冒泡排序\n时间: " << duration << "\t比较次数: " << compare[2] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;
}//将枢纽放在区间的最终位置 枢纽左侧的数小于枢纽,反之亦然
int partition(List &Ltemp,int low ,int high){
Ltemp.data[0] = Ltemp.data[low]; //暂时存枢纽 int pivotkey = Ltemp.data[low].num; //代替枢纽 方便比较 while(low < high){
while((low < high) && (Ltemp.data[high].num >= pivotkey)){
//j左移动 --high;compare[3]++;}if(low < high)Ltemp.data[low] = Ltemp.data[high]; //更换位置 while((low < high) && (Ltemp.data[low].num <= pivotkey)){
//i右移动 ++low;compare[3]++; }if(low < high)Ltemp.data[high] = Ltemp.data[low]; //更换位置 } Ltemp.data[low] = Ltemp.data[0]; //保存枢纽 return low; //返回枢纽下标
}void QSort(List &Ltemp,int low,int high){
int pivotloc; //记录枢纽位置if(low < high){
//当左右区间不重合时 compare[3]++; pivotloc = partition(Ltemp,low,high); //找到枢轴 QSort(Ltemp,low,pivotloc - 1); //对枢轴左右区间在进行快排 QSort(Ltemp,pivotloc+1,high); }return ;
}void QuickSort(List Ltemp){
//快排接口 交换排序的进阶 start = clock();QSort(Ltemp,1,Ltemp.length);stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "快速排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" <<endl; Timecost << "快速排序\n时间: " << duration << "\t比较次数: " << compare[3] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;
}//选择排序 每次选择一个极值放到合适位置
void SelectSort(List Ltemp){
int k,i,j;Data t;start = clock();for(i = 1;i < L.length;++i){
//每次都选择一个最小关键字记录 k = i;compare[4]++;for(j = i+1;j <= Ltemp.length;++j){
//如果比已经找到的关键字小就记录其下标compare[4]++;if(Ltemp.data[j].num < Ltemp.data[k].num ) k = j; //==确保稳定} if(k!=i){
//当需要交换时,才进行交换 t = Ltemp.data[i];Ltemp.data[i] = Ltemp.data[k];Ltemp.data[k] = t; } } stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "选择排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "选择排序\n时间: " << duration << "\t比较次数: " << compare[4];if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;
} void HeapAdjust(List &Ltemp,int s,int m){
//假设data[s+1……m]已经是堆,将data[s……m]调整为data[s]为根的大根堆Data rc = Ltemp.data[s]; //保存插入点 for(int j = 2*s;j <= m;j*=2){
compare[5]+=2; //记录比较次数 if(j < m && Ltemp.data[j].num < Ltemp.data[j+1].num) ++j;//找到左右孩子中大的那个 if(rc.num >= Ltemp.data[j].num) break; //比左右孩子都大 时说明找到了合适位置 Ltemp.data[s] = Ltemp.data[j];s = j; }Ltemp.data[s] = rc; //将插入点放在合适位置 return ;
} //建立堆 要保证每棵子树都是堆,所以要从每个有孩子的树先开始调整 当孩子有序后再调整父亲
void CreatHeap(List &Ltemp){
int n;n = Ltemp.length;for(int i = n/2;i>0;--i){
//叶子结点已经是堆 HeapAdjust(Ltemp,i,n); compare[5]++;}return ;
} //堆排序
void HeapSort(List Ltemp){
CreatHeap(Ltemp);Data x; //将最大堆堆顶后移至末尾(与末尾交换)这样就完成了从大到小的排序start = clock();for(int i = Ltemp.length;i>1;--i){
compare[5]++; x = Ltemp.data[1];Ltemp.data[1] = Ltemp.data[i]; //将堆顶取出 也就是最大值放在后面 Ltemp.data[i] = x;HeapAdjust(Ltemp,1,i-1); //重新新调整为大根堆 }stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "堆排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "堆排序\n时间: " << duration << "\t比较次数: " << compare[5] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;
} void merge(List &Ltemp,int left, int mid, int right) {
//归并两组有序数。从小的到大 插入到另一个数组pint index = 0;int i = left,j = mid + 1;while((i <= mid) && (j <= right)) {
//当左右区间指针都还没越界if(Ltemp.data[i].num <= Ltemp.data[j].num) {
//左的大 compare[6]++; S.data[index++] = Ltemp.data[i++];} else {
compare[6]++;S.data[index++] = Ltemp.data[j++]; //右的大 }}while(i <= mid) {
//如果左子表有剩余直接合并到p数组S.data[index++] = Ltemp.data[i++];compare[6]++;}while(j <= right) {
//如果右子表有剩余直接合并到p数组S.data[index++] = Ltemp.data[j++];compare[6]++;}i = 0;while(i < index){
Ltemp.data[left+i] = S.data[i];i++;} return ;
}void MergeSort(List &Ltemp ,int left, int right) {
//归并排序,从小到大,递归int mid;if(left < right){
//先将左右区间排好序 再将整个区间排好序compare[6]++;mid = (left + right) >> 1;MergeSort(Ltemp,left,mid);MergeSort(Ltemp,mid+1, right);merge(Ltemp,left, mid, right);}return ;
}void MSort(List Ltemp){
start = clock();MergeSort(Ltemp,1,Ltemp.length);stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "归并排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "归并排序\n时间: " << duration << "\t比较次数: " << compare[6] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;return ;
} int maxbit(List L1, int n) //辅助函数,求数据的最大位数
{
int maxData = L1.data[1].num; ///< 最大数/// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。for (int i = 2; i <= n; ++i){
if (maxData < L1.data[i].num)maxData = L1.data[i].num;}int d = 1;int p = 10;while (maxData >= p){
//p *= 10; // Maybe overflowmaxData /= 10;++d;}return d;}void RadixSort(List Ltemp, int n) //基数排序
{
int d = maxbit(Ltemp, Ltemp.length);Data *tmp = new Data[n+1];int *count = new int[10]; //计数器int i, j, k;int radix = 1;start = clock();for(i = 1; i <= d; i++) //进行d次排序{
for(j = 0; j < 10; j++){
//每次分配前清空计数器compare[7]++; count[j] = 0; }for(j = 1; j <= n; j++){
compare[7]++;k = (Ltemp.data[j].num / radix) % 10; //统计每个桶中的记录数count[k]++;}for(j = 1; j < 10; j++)count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶for(j = n; j > 0; j--) //将所有桶中记录依次收集到tmp中{
compare[7]++;k = (Ltemp.data[j].num / radix) % 10;tmp[count[k]] = Ltemp.data[j];count[k]--;}for(j = 1; j <= n; j++){
//将临时数组的内容复制到data中compare[7]++;Ltemp.data[j] = tmp[j];}radix = radix * 10;}stop = clock();duration=((double)(stop-start))/CLK_TCK;Record << "基数排序" << endl;for(int i = 1;i <= Ltemp.length;i++)Record << Ltemp.data[i].num << "\t"; Record << "\n\n\n" << endl;Timecost << "基数排序\n时间: " << duration << "\t比较次数: " << compare[7] ;if(stability(Ltemp))Timecost << "\t稳定\n" << endl;else Timecost << "\t不稳定\n" << endl;delete []tmp;delete []count;return ;
}int main(){
srand((unsigned)time(NULL));L.length = DATASIZE; //将数组长度标记为要求长度 getdt();Record.open("result.txt");Timecost.open("time.txt");Record << "数据量: " << DATASIZE <<endl; Timecost << "数据量: " << DATASIZE <<endl; CreateData(); //生成 DATASIZE 数量的随机数保存再文件 data.txt文件中 ReadData(); InsertSort(L);BubbleSort(L);SelectSort(L);ShellSort(L,dt);QuickSort(L);HeapSort(L);MSort(L); RadixSort(L,L.length);Record.close();Timecost.close();return 0;
}