《数据结构与算法》课程设计
30、排序综合
问题描述:
利用随机函数产生N个随机整数(20000以上),对这些数进行多种方法进行排序。
基本要求:
(1)至少采用三种方法实现上述问题求解(提示:可采用的方法有插入排序、希尔排序、起泡排序、快速排序、选择排序、堆排序、归并排序)。并把排序后的结果保存在不同的文件中;
(2)统计每一种排序方法的性能(以上机运行程序所花费的时间为准进行对比),找出其中两种较快的方法;
(3)如果采用4种或4种以上的方法者,可适当加分。
#include<iostream>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<fstream>
#include<algorithm>
using namespace std;
struct sortTime {
string name; //排序方法名
int time; //排序消耗时间
};
bool cmpSotTime(sortTime o, sortTime t) {
return o.time < t.time;
}
//直接插入排序
void InsertSort(vector<int> &vi, int length) {
int i, j, tmp;
for (i = 1; i < length; i++) {
if (vi[i] < vi[i - 1]) { //反序时
tmp = vi[i];
j = i - 1;
do { //找 vi[i] 的插入位置
vi[j + 1] = vi[j]; //将数据大于 vi[i] 的记录后移
j--;
} while (j >= 0 && vi[j] > tmp);
vi[j + 1] = tmp; //在 j+1 处插入 R[i]
}
}
}
//折半插入排序
void BinInsertSort(vector<int> &vi, int length) {
int i, j, low, high, mid, tmp;
for (i = 1; i < length; i++) {
if (vi[i] < vi[i - 1]) { //反序时
tmp = vi[i]; //将 vi[i] 保存到 tmp
low = 0, high = i - 1;
while (low <= high) { //在 vi[low...high] 中查找插入的位置
mid = (low + high) >> 1; //取中间位置
if (tmp < vi[mid]) {
high = mid - 1; //插入点在左半区
} else {
low = mid + 1; //插入点在又半区
}
} //找位置 high
for (j = i - 1; j >= high + 1; j--) { //集中进行元素后移
vi[j + 1] = vi[j];
}
vi[high + 1] = tmp; //插入 tmp
}
}
}
//希尔排序
void ShellSort(vector<int> &vi, int length) {
int d = 1;
while (d < length / 3) { //设置增量
d = 3 * d + 1;
}
while (d >= 1) {
for (int i = d; i < length; i++) { //对所有组采用直接插入排序
for (int j = i; j >= d && vi[j] < vi[j - d]; j -= d) { //对相隔 d 个位置一组采用直接插入排序
swap(vi[j], vi[j - d]);
}
}
d = d / 3; //减小增量
}
}
//冒泡排序
void BubbleSort(vector<int> &vi, int length) {
int i, j;
bool exchange;
for (i = 0; i < length; i++) {
exchange = false; //一趟前 exchange 置为假
for (j = length - 1; j > i; j--) { //归位 vi[i],循环 length-i-1 次
if (vi[j] < vi[j - 1]) { //相邻两个元素反序时
swap(vi[j], vi[j - 1]); //将 vi[j] 和 vi[j-1] 两个元素交换
exchange = true; //一旦有交换,exchange 置为真
}
}
if (!exchange) { //本趟没有发生交换,中途结束算法
return;
}
}
}
//快速排序
void QuickSort(vector<int> &vi, int l, int r) {
if (l >= r) return;
int tmp = vi[(l + r) >> 1], i = l - 1, j = r + 1; //用区间中间元素作为基准
while (i < j) {
do i++; while (vi[i] < tmp); //从左向右扫描,找一个大于 tmp 的 vi[i]
do j--; while (vi[j] > tmp); //从右向左扫描,找一个小于 tmp 的 vi[j]
if (i < j) swap(vi[i], vi[j]); //交换大于 tmp 的 vi[i] 和小于 tmp 的 vi[j]
}
QuickSort(vi, l, j); //对左区间递归排序
QuickSort(vi, j + 1, r); //对右区间递归排序
}
//选择排序
void SelectSort(vector<int> &vi, int length) {
int i, j, k;
for (i = 0; i < length - 1; i++) { //做第 i 趟排序
k = i;
for (j = i + 1; j < length; j++) { //在当前无序区 vi[i...length-1] 中选数据最小的 vi[k]
if (vi[j] < vi[k]) {
k = j; //k 记下目前找到的最小数据所在的位置
}
}
if (k != i) { //vi[i] 和 vi[k] 两个元素交换
swap(vi[i], vi[k]);
}
}
}
//构造大根堆
void sift(vector<int> &vi, int low, int high) {
int i = low, j = 2 * i + 1; //vi[j] 是 vi[i]的左孩子
int tmp = vi[i];
while (j <= high) {
if (j + 1 <= high && vi[j] < vi[j + 1]) { //若右孩子较大,把 j 指向右孩子
j++;
}
if (vi[i] > vi[j]) { //若根结点大于等于最大孩子关键字,筛选结束
break;
} else { //若根结点小于最大孩子的关键字
swap(vi[i], vi[j]); //将 vi[j] 调整到双亲结点的位置上
i = j; //修改 i 和 j 值,以便继续向下筛选
j = i * 2 + 1;
}
}
vi[i] = tmp; //被筛选结点放入最终位置上
}
//堆排序
void HeapSort(vector<int> &vi, int length) {
for (int i = (length >> 1) - 1; i >= 0; i--) { //循环建立初始堆,调用 sift 算法 ⌊n/2⌋ 次
sift(vi, i, length - 1);
}
for (int i = length - 1; i >= 0; i--) { //进行 n-1 趟完成堆排序,每一趟堆中元素个数减 1
swap(vi[0], vi[i]); //将最后一个元素与根 vi[1] 交换
sift(vi, 1, i - 1); //对 vi[1...i-1] 进行筛选,得到 i1 个结点的堆
}
}
//二路归并排序
const int N = 1000010;
int tmp[N];
void MergeSort(vector<int> &vi, int l, int r) {
if (l >= r) return;
int mid = l + r >> 1; //取中间位置
MergeSort(vi, l, mid), MergeSort(vi, mid + 1, r); //递归分组
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) {
if (vi[i] <= vi[j]) tmp[k++] = vi[i++]; //从小到大加进 tmp
else tmp[k++] = vi[j++];
}
while (i <= mid) tmp[k++] = vi[i++]; //将剩余元素加进 tmp
while (j <= r) tmp[k++] = vi[j++]; //将剩余元素加进 tmp
for (i = l, j = 0; i <= r; i++, j++) vi[i] = tmp[j];
}
int main() {
srand((unsigned) time(NULL));
int length;
cout << "请输入随机数的个数:";
cin >> length;
vector<int> insertArray, binInsertArray, shellArray, bubbleArray, quickArray, selectArray, heapArray, mergeArray;
cout << "开始生成随机数...\n";
for (int i = 0, t; i < length; i++) {
t = rand();
insertArray.push_back(t);
binInsertArray.push_back(t);
shellArray.push_back(t);
bubbleArray.push_back(t);
quickArray.push_back(t);
selectArray.push_back(t);
heapArray.push_back(t);
mergeArray.push_back(t);
}
cout << "随机数生成完毕!\n开始进行排序...\n";
clock_t start; //定时器
sortTime st[8];
start = clock();
InsertSort(insertArray, insertArray.size());
st[0].name = "直接插入排序", st[0].time = clock() - start;
start = clock();
BinInsertSort(binInsertArray, binInsertArray.size());
st[1].name = "折半插入排序", st[1].time = clock() - start;
start = clock();
ShellSort(shellArray, shellArray.size());
st[2].name = "希尔排序", st[2].time = clock() - start;
start = clock();
BubbleSort(bubbleArray, bubbleArray.size());
st[3].name = "冒泡排序", st[3].time = clock() - start;
start = clock();
QuickSort(quickArray, 0, quickArray.size() - 1);
st[4].name = "快速排序", st[4].time = clock() - start;
start = clock();
SelectSort(selectArray, selectArray.size());
st[5].name = "选择排序", st[5].time = clock() - start;
start = clock();
HeapSort(heapArray, heapArray.size());
st[6].name = "堆排序", st[6].time = clock() - start;
start = clock();
MergeSort(mergeArray, 0, mergeArray.size() - 1);
st[7].name = "二路归并排序", st[7].time = clock() - start;
cout << "排序完毕!开始将数据写入文件...\n";
//开流
ofstream insertSortOutStream("../CurriculumDesign/data/InsertSort.txt", ios::out);
ofstream binInsertSortOutStream("../CurriculumDesign/data/BinInsertSort.txt", ios::out);
ofstream shellSortOutStream("../CurriculumDesign/data/ShellSort.txt", ios::out);
ofstream bubbleSortOutStream("../CurriculumDesign/data/BubbleSort.txt", ios::out);
ofstream quickSortOutStream("../CurriculumDesign/data/QuickSort.txt", ios::out);
ofstream selectSortOutStream("../CurriculumDesign/data/SelectSort.txt", ios::out);
ofstream heapSortOutStream("../CurriculumDesign/data/HeapSort.txt", ios::out);
ofstream mergeSortOutStream("../CurriculumDesign/data/MergeSort.txt", ios::out);
//写数据
insertSortOutStream << "直接插入排序:\n" << "时间消耗:" << st[0].time << "ms\n";
binInsertSortOutStream << "折半插入排序:\n" << "时间消耗:" << st[1].time << "ms\n";
shellSortOutStream << "希尔排序:\n" << "时间消耗:" << st[2].time << "ms\n";
bubbleSortOutStream << "冒泡排序:\n" << "时间消耗:" << st[3].time << "ms\n";
quickSortOutStream << "快速排序:\n" << "时间消耗:" << st[4].time << "ms\n";
selectSortOutStream << "选择排序:\n" << "时间消耗:" << st[5].time << "ms\n";
heapSortOutStream << "堆排序:\n" << "时间消耗:" << st[6].time << "ms\n";
mergeSortOutStream << "二路归并排序:\n" << "时间消耗:" << st[7].time << "ms\n";
for (int i = 0; i < length; i++) {
insertSortOutStream << insertArray[i] << '\n';
binInsertSortOutStream << binInsertArray[i] << '\n';
shellSortOutStream << binInsertArray[i] << '\n';
bubbleSortOutStream << binInsertArray[i] << '\n';
quickSortOutStream << binInsertArray[i] << '\n';
selectSortOutStream << binInsertArray[i] << '\n';
heapSortOutStream << binInsertArray[i] << '\n';
mergeSortOutStream << binInsertArray[i] << '\n';
}
cout << "数据写入文件完毕!\n";
//关流
insertSortOutStream.close();
binInsertSortOutStream.close();
shellSortOutStream.close();
bubbleSortOutStream.close();
quickSortOutStream.close();
selectSortOutStream.close();
heapSortOutStream.close();
mergeSortOutStream.close();
sort(st, st + 8, cmpSotTime);
cout << "第一快的排序方法:" << st[0].name << "时间消耗:" << st[0].time << "ms\n";
cout << "第二快的排序方法:" << st[1].name << "时间消耗:" << st[1].time << "ms\n";
return 0;
}