浙大陈越数据结构-09-排序1 排序

冒泡排序

冒泡排序不做任何优化:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void sort(vector<int>& nums){
    int size = nums.size();
    for(int i = size - 1; i > 0; i--){
        for(int j = 0; j < i; j++){
            if(nums[j] > nums[j + 1]){
                swap(nums[j], nums[j + 1]);
            }
        }
    }
}



int main(){
    int n;
    cin >> n;
    vector<int> nums(n, 0);
    for(int i = 0; i < n; i++){
        cin >> nums[i];
    }
    sort(nums);
    for(int i = 0; i < n; i++){
        if(i == n - 1)
            cout << nums[i];
        else
            cout << nums[i] << " ";
    }

}

有两个点超时了,做一点优化看看,增加一个标志,当没有发生交换时,就说明数据已经有序,可以停止了。 

 依旧超时。在加一点优化,每次循环判断最后一次交换的位置,下次交换到上一轮最后一次交换的位置即可。

void sort(vector<int>& nums){
    int size = nums.size();
    int lastSwap = size - 1;
    while(lastSwap > 0){
        bool flag = false;
        int lastTmp = lastSwap;
        for(int j = 0; j < lastSwap; j++){
            if(nums[j] > nums[j + 1]){
                flag = true;
                swap(nums[j], nums[j + 1]);
                lastTmp = j;
            }
        }
        if(!flag)
            break;
        lastSwap = lastTmp;
    }
}

 还是超时,冒泡排序时间复杂度为O(n^2),可能是太高了,再试试其他几个排序方法。

插入排序

void sort(vector<int>& nums){
    int size = nums.size();
    for(int i = 1; i < size; i++){
        int tmpNum = nums[i];
        int tmpIndex = i - 1;
        while(tmpIndex >= 0 && nums[tmpIndex] > tmpNum){
            nums[tmpIndex + 1] = nums[tmpIndex];
            tmpIndex--;
        }
        nums[tmpIndex + 1] = tmpNum;
    }
}

 插入排序时间复杂度也是O(N^2),但是要比冒泡排序快一些。

选择排序

原始版本

void sort(vector<int>& nums){
    int size= nums.size();
    for(int i = 0; i < size; i++){
        int min = i;
        int minNum = nums[i];
        for(int j = i + 1; j < size; j++){
            if(nums[j] < minNum){
                minNum = nums[j];
                min = j;
            }
        }
        swap(nums[i], nums[min]);
    }
}

 用时都很长,优化一下。在一次循环中找最大值和最小值,这样外循环次数可以减少一半。

void sort(vector<int>& nums){
    int size = nums.size();
    int halfSize = size >> 1;
    int minIndex, minNum, maxIndex, maxNum;
    for(int i = 0; i < halfSize; i++){
        minIndex = maxIndex = i;
        minNum = maxNum = nums[i];
        for(int j = i + 1; j < size - i; j++){
            if(nums[j] < minNum){
                minNum = nums[j];
                minIndex = j;
            }
            if(nums[j] > maxNum){
                maxNum = nums[j];
                maxIndex = j;
            }
        }
        if(maxIndex == minIndex)
            break;
        swap(nums[i], nums[minIndex]);
        if(maxIndex == i){
            maxIndex = minIndex;
        }
        swap(nums[maxIndex], nums[size - 1 - i]);
    }
}

 比上次的好了一些,但是选择排序总体上不如插入排序。

希尔排序

使用了Sedgewich增量序列,因为题目中给的最大元素数量是10^5个,所以手动生成增量序列,然后使用希尔排序。

void sort(vector<int>& nums){
    int Sedgewich[] = {64769, 36289, 16001, 8929, 3905, 2161, 929,505,209, 109, 41,19, 5,1, 0};
    int size = nums.size();
    int sIndex = 0;
    for(; Sedgewich[sIndex] >= size; sIndex++);
    for(int d = Sedgewich[sIndex]; d > 0; d = Sedgewich[++sIndex]){
        for(int i = d; i < size; i++){
            int tmpNum = nums[i];
            int preIndex = i - d;
            while(preIndex >= 0 && tmpNum < nums[preIndex]){
                nums[preIndex + d] = nums[preIndex];
                preIndex -= d;
            }
            nums[preIndex + d] = tmpNum;
        }
    }
}

 用时缩短了好多。

接下来的排序算法时间复杂度都是O(NlogN)的。

堆排序

void PercDown(vector<int>& nums, int p, int size){
    int parentIndex, childIndex;
    int tmpNum = nums[p];
    for(parentIndex = p; (parentIndex << 1) + 1 < size; parentIndex = childIndex){
        childIndex = (parentIndex << 1) + 1;
        if(childIndex < size - 1 && nums[childIndex] < nums[childIndex + 1])
            childIndex++;
        if(nums[childIndex] > tmpNum){
            nums[parentIndex] = nums[childIndex];
        }
        else
            break;
    }
    nums[parentIndex] = tmpNum;
}

void sort(vector<int>& nums){
    int i;
    int size = nums.size();
    for(i = (size >> 1) - 1; i >= 0; i--){
        PercDown(nums, i, size);
    }
    for(i = size - 1; i > 0; i--){
        swap(nums[i], nums[0]);
        PercDown(nums, 0, i);
    }
}

 快速排序

int getMiddle(vector<int>& nums, int start, int end){
    int baseNumIndex = start + rand() % (end - start + 1);
    if(end != baseNumIndex)
        swap(nums[end], nums[baseNumIndex]);
    int baseNumber = nums[end];
    int i = start;
    for(int j = start; j < end; j++){
        if(nums[j] < baseNumber){
            swap(nums[j], nums[i]);
            i++;
        }
    }
    swap(nums[i], nums[end]);
    return i;
}

void quickSort(vector<int>& nums, int start, int end){
    if(start >= end)
        return;
    int middle = getMiddle(nums, start, end);
    quickSort(nums, start, middle - 1);
    quickSort(nums, middle + 1, end);
}

void sort(vector<int>& nums){
    quickSort(nums, 0, nums.size() - 1);
}

 并归排序

void merge(vector<int>& nums, int start, int end, int middle){
    int index1 = start;
    int index2 = middle + 1;
    vector<int> tmp(end - start + 1, 0);
    int tmpIndex = 0;
    while(index1 <= middle && index2 <= end){
        int num1 = nums[index1];
        int num2 = nums[index2];
        int take = num1 < num2;
        tmp[tmpIndex++] = take ? num1 : num2;
        index1 += take;
        index2 += 1-take;
    }
    while(index1 <= middle){
        tmp[tmpIndex++] = nums[index1++];
    }
    while(index2 <= end){
        tmp[tmpIndex++] = nums[index2++];
    }
    int size = tmp.size();
    for(int i = 0; i < size; i++){
        nums[start + i] = tmp[i];
    }
}

void merge_sort(vector<int>& nums, int start, int end){
    if(start >= end)
        return;
    int middle = (start + end) >> 1;
    merge_sort(nums, start, middle);
    merge_sort(nums, middle + 1, end);
    merge(nums,start, end, middle);
}

void sort(vector<int>& nums){
    merge_sort(nums, 0, nums.size()  - 1);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值