912. 排序数组

15.1 选择排序

  1. class Solution {
  2. public:
  3. void swap(int& a,int &b){
  4. int temp=a;
  5. a=b;
  6. b=temp;
  7. }
  8. vector<int> sortArray(vector<int>& nums) {
  9. int n=nums.size();
  10. for(int i=0;i<n-1;i++){
  11. //找最小的元素
  12. int min=i;
  13. for(int j=i+1;j<n;j++){
  14. if(nums[j]<nums[min]){
  15. min=j;
  16. }
  17. }
  18. //交换
  19. swap(nums[min],nums[i]);
  20. }
  21. return nums;
  22. }
  23. };

15.2 插入排序

超时,适合数据量小或部分有序数据

  1. class Solution {
  2. public:
  3. vector<int> sortArray(vector<int>& nums) {
  4. if(nums.size()<2){
  5. return nums;
  6. }
  7. int n=nums.size();
  8. for(int i=1;i<n;i++){
  9. int temp=nums[i];
  10. //从后到前扫描已排好序的集合,找到合适位置为k+1
  11. int k=i-1;
  12. while(k>=0&&nums[k]>temp){
  13. k--;
  14. }
  15. //腾出位置,从k之后全部后移一位,直到i
  16. for(int j=i;j>k+1;j--){
  17. nums[j]=nums[j-1];
  18. }
  19. nums[k+1]=temp;
  20. }
  21. return nums;
  22. }
  23. };

15.3 冒泡排序

  1. class Solution {
  2. public:
  3. void swap(int& a,int& b){
  4. int t=a;a=b;b=t;
  5. }
  6. vector<int> sortArray(vector<int>& nums) {
  7. if(nums.size()<2){
  8. return nums;
  9. }
  10. int n=nums.size();
  11. //比较n-1轮
  12. for(int i=0;i<n-1;i++){
  13. //第i+1趟时比较n-1-i次,从头开始比较
  14. for(int j=0;j<n-i-1;j++){
  15. if(nums[j+1]<nums[j]){
  16. swap(nums[j+1],nums[j]);
  17. }
  18. }
  19. }
  20. return nums;
  21. }
  22. };

15.4 希尔排序

  1. class Solution {
  2. public:
  3. vector<int> sortArray(vector<int>& nums) {
  4. if(nums.size()<2){
  5. return nums;
  6. }
  7. int n=nums.size();
  8. // 对每组间隔为 gap 的分组进行排序,刚开始 gap = n / 2;
  9. for(int gap=n/2;gap>0;gap/=2){
  10. //对每个局部分组进行插入排序
  11. //轮流对每个组进行插入排序,并不是先对一个组排序完了再来对另一个组排序
  12. for(int i=gap;i<n;i++){
  13. insertSort(nums,gap,i);
  14. }
  15. }
  16. return nums;
  17. }
  18. //gap为增量
  19. //arr[i]] 所在的分组为 ... arr[i-2*gap],arr[i-gap], arr[i+gap] ...
  20. void insertSort(vector<int>& nums,int gap,int i){
  21. int temp=nums[i];
  22. int k;
  23. //从后往前扫描,找到合适位置插入
  24. for(k=i-gap;k>=0&&temp<nums[k];k-=gap){
  25. nums[k+gap]=nums[k];
  26. }
  27. nums[k+gap]=temp;
  28. }
  29. };

15.5 合并排序

  1. class Solution {
  2. public:
  3. vector<int> sortArray(vector<int>& nums) {
  4. if(nums.size()<2){
  5. return nums;
  6. }
  7. int n=nums.size();
  8. mergeSort(nums,0,n-1);
  9. return nums;
  10. }
  11. //递归,终止条件,只有一个元素时left==right
  12. void mergeSort(vector<int>& nums,int left,int right){
  13. if(left<right){
  14. //分成两部分
  15. int mid=left+(right-left)/2;
  16. mergeSort(nums,left,mid);
  17. mergeSort(nums,mid+1,right);
  18. //合并两个有序队列
  19. merge(nums,left,mid,right);
  20. }
  21. }
  22. void merge(vector<int>& nums,int left,int mid,int right){
  23. //从两个有序数组中分别取数比较大小,结果放到辅助数组中。
  24. int i=left,j=mid+1,k=0;
  25. vector<int> temp(nums.size());
  26. while(i<=mid&&j<=right){
  27. if(nums[i]<=nums[j]){
  28. temp[k++]=nums[i++];
  29. }else{
  30. temp[k++]=nums[j++];
  31. }
  32. }
  33. while(i<=mid){
  34. temp[k++]=nums[i++];
  35. }
  36. while(j<=right){
  37. temp[k++]=nums[j++];
  38. }
  39. //复制到原数组
  40. for(int i=0;i<k;i++){
  41. nums[left++]=temp[i];
  42. }
  43. }
  44. };
//非递归
 vector<int> mergeSort(vector<int>& nums){
        int n=nums.size();
        // 子数组的大小分别为1,2,4,8...
        // 刚开始合并的数组大小是1,接着是2,接着4....
        for(int i=1;i<n;i+=i){
            int left=0;
            int mid=left+i-1;
            int right=mid+i;
            while(right<n){
                merge(nums,left,mid,right);
                left=right+1;
                mid=left+i-1;
                right=mid+i;
            }
              // 还有一些被遗漏的数组没合并,千万别忘了
            // 因为不可能每个字数组的大小都刚好为 i
            if(left<n&&mid<n){
                merge(nums,left,mid,n-1);
            }
        }
        return nums;
    }

15.6 快速排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        if(nums.size()<2){
            return nums;
        }
        quickSort(nums,0,nums.size()-1);
        return nums;
    }
    void quickSort(vector<int>& nums,int left,int right){
        if(left<right){
            //获取中轴元素的位置
            int mid=partition(nums,left,right);
            quickSort(nums,left,mid-1);
            quickSort(nums,mid+1,right);
        }
    }
    int partition(vector<int>& nums,int left,int right){
        int pivot=nums[left];
        int i=left+1,j=right;
        while(1){
            //i从前往后找,j从后往前找
            while(i<=j&&nums[i]<=pivot) i++;
            while(i<=j&&nums[j]>=pivot) j--;
            //i==j退出
            if(i>=j) break;
            //交换i j元素
            int temp=nums[i];
            nums[i]=nums[j];
            nums[j]=temp;
        }
        //交换有序的位置nums[j]和中轴元素nums[left]
        nums[left]=nums[j];
        nums[j]=pivot;
        return j;
    }
};
class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand(time(0));
        if(nums.size()<2) return nums;
        quickSort(nums,0,nums.size()-1);
        return nums;
    }

    void quickSort(vector<int>& nums,int left,int right){
        if(left<right){
            int mid=partition(nums,left,right);
            quickSort(nums,left,mid-1);
            quickSort(nums,mid+1,right);
        }
    }

    int partition(vector<int>& nums,int left,int right){
        int a=rand()%(right-left+1)+left;
        swap(nums[a],nums[left]);

        int priot=nums[left];
        int i=left+1,j=right;
        while(1){
            while(i<=j && nums[i]<=priot) i++;
            while(i<=j && nums[j]>=priot) j--;
            if(i>=j) break;
            swap(nums[i],nums[j]);
        }        
        nums[left]=nums[j];
        nums[j]=priot;
        return j;
    }
};

15.7 堆排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        if(nums.size()<2){
            return nums;
        }
        heapSort(nums);
        return nums;
    }
    vector<int> heapSort(vector<int>& nums){
        //构建大顶堆
        int n=nums.size();
        //对所有非叶子节点进行下沉
        for(int i=(n-2)/2;i>=0;i--){
            downAdjust(nums,i,n-1);
        }
        //堆排序:堆顶元素为最小的元素,取出保存起来,为节约空间,直接保存在堆的末尾
        //即:交换堆顶与末尾元素
        for(int i=n-1;i>=1;i--){
            int temp=nums[i];
            nums[i]=nums[0];
            nums[0]=temp;
            //交换后调整剩余的堆
            downAdgust(nums,0,i-1);
        }
        return nums;
    }

    //下沉
    void downAdjust(vector<int>& nums,int parent,int length){
        //左孩子
        int child=parent*2+1;
        //临时保存要下沉的元素用于后续比较
        int temp=nums[parent];
        while(child<=length){
            //左右孩子中更小的一个与父交换
            if(child+1<=length && nums[child]<nums[child+1]){
                child++;
            }
            if(temp>=nums[child]){
                break;
            }
            //交换
            nums[parent]=nums[child];
            //下沉后下标改变
            parent=child;
            child=2*parent+1;
        }
        //已经下沉,赋值
        nums[parent]=temp;
    }
};

15.8 计数排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        if(nums.size()<2){
            return nums;
        }
        //优化做法:根据最大最小值之差来确定临时数组大小
        int m_max=nums[0];
        int m_min=nums[0];
        int n=nums.size();
        for(int i=1;i<n;i++){
            if(m_max<nums[i]){
                m_max=nums[i];
            }
            if(m_min>nums[i]){
                m_min=nums[i];
            }
        }

        //创建临时数组
        int d=m_max-m_min+1;
        vector<int> temp(d);
        //统计每个元素出现的次数
        for(int i=0;i<n;i++){
            temp[nums[i]-m_min]++;
        }
        //根据临时数组汇总到原数组
        int k=0;
        for(int i=0;i<d;i++){
            for(int j=temp[i];j>0;j--){
                nums[k++]=i+m_min;
            }
        }
        return nums;
    }
};

15.9 桶排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        if(nums.size()<2){
            return nums;
        }
        int m_max=nums[0];
        int m_min=nums[0];
        int n=nums.size();
        for(int i=1;i<n;i++){
            if(m_max<nums[i]){
                m_max=nums[i];
            }
            if(m_min>nums[i]){
                m_min=nums[i];
            }
        }

        int d=m_max-m_min;
        //初始化桶,创建 d / 5 + 1 个桶,第 i 桶存放  5*i ~ 5*i+5-1范围的数
        int bucketNum=d/5+1;        
        //gap为5,或者当bucketNum为时,gap为 (m_max-m_min)/(bucketNum-1),序号为(num[i]-m_min)/d
        vector<list<int>> bucketList(bucketNum);
        for(int i=0;i<n;i++){
            //计算bucket序号
            int num=(double)(nums[i]-m_min)/5;
            //将元素装入对应桶中
            bucketList[num].push_back(nums[i]-m_min);
        }

        //每个桶中进行排序
        for(int i=0;i<bucketNum;i++){
            bucketList[i].sort();
        }
        //放回原数组
        int k=0;
        for(int i=0;i<bucketNum;i++){
            for(auto& b:bucketList[i] ){
                nums[k++]=b+m_min;
            }
        }
        return nums;
    }
};

15.10 基数排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        if(nums.size()<2){
            return nums;
        }
        int n=nums.size();
        //计算需要几轮,找最大元素,看其是几位数
        int num=nums[0];
        int m_max=0;
        for(int i=0;i<n;i++){
            m_max=max(m_max,nums[i]);
        }
        while(m_max/10>0){
            num++;
            m_max=m_max/10;
        }

        vector<list<int>> bucketList(10);
        //每一轮,进行每一趟的排序,从个位数开始
        for(int m=0;m<num;m++){
            for(int i=0;i<n;i++){
                int temp=nums[i];
                //求个位数、十位数、百位数 
                for(int j=0;j<m;j++){
                    temp/=10;
                }
                //temp%10为桶序号,放到对应桶中
                bucketList[temp%10].push_back(nums[i]);
            }

            //放回原数组
            int k=0;
            for(int j=0;j<10;j++){
                for(auto& b:bucketList[j] ){
                    nums[k++]=b;
                }
                //取出后把桶清空
                bucketList[j].clear();
            }
        }
        return nums;
    }
};

15. 排序算法 - 图1