DreamJudge-1106-排序2
1.题目描述
Time Limit: 1000 ms
Memory Limit: 256 mb
编写程序实现直接插入排序、希尔排序(d=5)、直接选择排序、快速排序和二路归并排序算法。
输入输出格式
输入描述:
第一行是待排序数据元素的个数; 待排序的数据元素。
输出描述:
直接插入排序后的结果 一趟希尔排序后的结果 直接选择排序后的结果 快速排序后的结果 一趟二路归并排序后的结果
输入输出样例
输入样例#:
10
50 36 41 19 23 4 20 18 12 22
输出样例#:
4 12 18 19 20 22 23 36 41 50
4 20 18 12 22 50 36 41 19 23
4 12 18 19 20 22 23 36 41 50
4 12 18 19 20 22 23 36 41 50
36 50 19 41 4 23 18 20 12 22
2.题解
2.1 多排序总结
思路
这里一共总结了:
1.插入排序(保证前面的一段有序序列,并不断往后插入),
2.希尔排序(这里的是一次希尔排序,步长d=5, 相当于只进行一次d=5的插排即可,无需将 d = n / 2, d = d / 2 这样迭代步长),
比较新的一种是基于插入排序优化的希尔排序,基于插入排序优化,将原有的插排转换为分组插排,是一种分治思想,由于步长拉大,较小的数据能更快接近前面他应该在的位置,而不用一个一个往前判断,较大的同理。
3.直接选择排序(保证每次遍历最首段的数是最小的),
4.二路快速排序(这里采用分治思想,确定一个基准点,然后比他小的放左边,比他大的放右边,最后将这个数放在left和right重合处,也就是他应该在的地方,这样该数位置确定,左右数列被分区,在更小的数列中进行迭代重复上述操作,每次确定一个基准点位置)
- 时间复杂度:平均情况 nlog(n)
5.二路归并排序(分治思想,分组再归并,确定一个mid位置,然后分为左右两组,通过递归保证传回来的左右数列都是有序的,然后再合并这两个数列(两个有序合并为一个操作较为简单))
代码
#include<bits/stdc++.h>
using namespace std;
vector<int> a, b, c;
// 插入排序
// 保证左侧一个有序数组序列
void insertSort(vector<int> &a){
int n = a.size();
for(int i = 1, j; i < n; i++){
int num = a[i];
// 插入排序,如果大于该数,就往后移,为其空出位置;
// 否则跳出循环,j + 1位放该数
for(j = i - 1; j >= 0 && a[j] > num; j--){
a[j + 1] = a[j];
}
a[j + 1] = num;
}
}
// 希尔排序
// 希尔排序逻辑上是一组插入排序完再进行另一组的,实际代码中则不是按分组顺序,而是按数组顺序遍历,遇到哪个往前找一个gap
void shellSort(vector<int>& arr) {
int n = arr.size();
// 进行分组,确定gap,且gap不断迭代
for (int gap = n / 2; gap > 0; gap /= 2) {
// 每一组的具体情况
for (int i = gap, j; i < n; ++i) {
int temp = arr[i];
// 内层是插入排序,不过间距是gap
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
arr[j] = arr[j - gap];
}
arr[j] = temp;
}
}
}
// 一次希尔排序(d = 5)
void shellSort_d5(vector<int>& arr) {
int n = arr.size();
// 进行分组,确定gap,且gap不断迭代
int gap = 5;
// 每一组的具体情况
for (int i = gap, j; i < n; ++i) {
int temp = arr[i];
// 内层是插入排序,不过间距是gap
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
arr[j] = arr[j - gap];
}
arr[j] = temp;
}
}
// 直接选择排序
// 保证每次最左侧的都是最小的
void selectionSort(vector<int>& arr){
// 表示遍历次数
int n = arr.size();
for(int i = 1; i < n; i++){
for(int j = i; j < n; j++){
if(arr[j] < arr[i-1]){
swap(arr[j], arr[i-1]);
}
}
}
}
// 双路快速排序
// 分治算法
int Paritition(vector<int>&arr, int low, int high){
int pivot = arr[low]; // 将arr[low]作为基准点
while(low < high){
while(low < high && arr[high] > pivot){
high--;
}
arr[low] = arr[high];
while(low < high && arr[low] < pivot){
low++;
}
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
// 迭代函数
void quickSort(vector<int>& arr, int low, int high){
// 分组
if(low >= high) return; // 不要忘记迭代终止条件
int medium = Paritition(arr, low, high);
// 继续快排(medium位置已经确定,无需继续参与)
quickSort(arr, low, medium - 1);
quickSort(arr, medium + 1, high);
}
void quickSort(vector<int>& arr){
int n = arr.size();
quickSort(arr, 0, n - 1);
}
// 二路归并排序
// 分治算法
vector<int> t;
void mergeSort(vector<int>& arr, int low, int high){
// 终止条件
if(low >= high) return;
// 分治 (确保两侧都是有序的)
int mid = (low + high) >> 1;
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
// 合并
int cnt = 0; // 用来记录这一轮合并的个数并用作下标
int l = low, r = mid + 1;
while(l <= mid && r <= high){
if(arr[l] < arr[r]) t[cnt++] = arr[l++];
else t[cnt++] = arr[r++];
}
// 清理剩余部分
while(l <= mid) t[cnt++] = arr[l++];
while(r <= high) t[cnt++] = arr[r++];
// 更新数组
for(int i = 0; i < cnt; i++){
arr[low + i] = t[i];
}
}
// 一次归并排序(只进行最内层两个两个的排序)
void mergeSort_once(vector<int>& arr){
int n = arr.size();
if(n%2==0){
for(int i=0;i<n-1;i=i+2){
if(a[i]>a[i+1]){
swap(a[i],a[i+1]);
}
}
}
else{
for(int i=0;i<n-2;i=i+2){
if(a[i]>a[i+1]){
swap(a[i],a[i+1]);
}
}
}
}
// 归并排序
void mergeSort(vector<int>& arr){
int n = arr.size();
t.resize(n);
// mergeSort(arr, 0, n - 1);
mergeSort_once(arr);
}
// 打印数组
void printArr(vector<int> &x){
for(int num : x){
cout << num << " ";
}
cout << endl;
}
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
int num;
cin >> num;
a.push_back(num);
}
b.resize(a.size());
copy(a.begin(), a.end(), b.begin());
// 插入排序
insertSort(a);
printArr(a);
// 希尔排序
copy(b.begin(), b.end(), a.begin());
shellSort_d5(a);
printArr(a);
// 直接选择排序
copy(b.begin(), b.end(), a.begin());
selectionSort(a);
printArr(a);
// 双路快速排序
copy(b.begin(), b.end(), a.begin());
quickSort(a);
printArr(a);
// 一次二路归并排序
copy(b.begin(), b.end(), a.begin());
mergeSort(a);
printArr(a);
return 0;
}