• 【C++、partition】快速排序算法实现


    算法思想

    快速排序也采用分治思想;
    把原始的数组筛选成较小和较大两个子数组,然后递归地排序两个子数组;
    在分成较小和较大的两个子数组过程中,如何选定基准值很关键。

    代码实现

    partition部分

    • 随机选取基准值,放到数组末尾
    • 遍历数组(0-基准值前,不包括最后的基准值),逐个比较每个数与基准值的大小,只考虑两种情况:不比基准值大、比基准值大;
    • 借助i和j两个下标索引,j负责逐个遍历数组元素,i负责记录当前不大于基准值的尾后位置(有点绕,看代码),将不比基准值大的数按顺序交换到数组头,从数组头往数组尾生长;
    • 最后,把尾部基准值交换到i当前位置
    #include<iostream>
    #include<vector>
    #include<random>
    using namespace std;
    
    void swap(vector<int>& nums, int m, int n);
    int randRange(int low, int high);
    int partition(vector<int>& nums, int low, int high);
    
    //快速排序主体
    void quicksort(vector<int>& nums, int low, int high) {
    	if (low >= high) return;//如果只剩下一个元素,返回
    	int p = partition(nums, low, high);//找到分割点,左半部分都不比它大,右半部分都比它大
    	quicksort(nums, low, p - 1);//递归
    	quicksort(nums, p + 1, high);
    }
    
    //使得被选出的基准值,都是当前子数组中的中间数
    inline int partition(vector<int> &nums, int low, int high) {
    	swap(nums, randRange(low, high), high);//避免最糟糕的情况出现,随机选值放到最右端
    	int i=0, j=0;
    	for (i = low, j = low;j < high;++j) {
    		if (nums[j] <= nums[high]) {
    			swap(nums, i++, j);
    		}
    	}
    	swap(nums, i, j);
    	return i;
    }
    
    //针对数组,将指定的两个坐标对应的数交换
    inline void swap(vector<int> &nums, int m, int n) {
    	std::swap(nums[m], nums[n]);
    }
    
    //从指定的范围,随机选取一个整数
    inline int randRange(int low, int high) {
    	uniform_int_distribution<int> u(low, high);
    	default_random_engine e;//生成无符号随机整数
    	return u(e);
    }
    
    //打印数组
    void printVector(const vector<int>& a) {
    	for (auto i : a) {
    		cout << i << " ";
    	}
    	cout << endl;
    }
    
    int main(int argc, char** argv) {
    	vector<int> a{ 5,6,4,2,3 };
    	quicksort(a, 0, a.size() - 1);
    	printVector(a);
    	return 0;
    }
    
    

    换汤不换药,下面这份代码没有那么短小函数:

    #include<iostream>
    #include<vector>
    #include<random>
    using namespace std;
    
    int partition1(vector<int>& nums, int low, int high);
    
    //快速排序主体
    void quicksort(vector<int>& nums, int low, int high) {
    	if (low >= high) return;//如果只剩下一个元素,返回
    	int p = partition1(nums, low, high);//找到分割点,左半部分都不比它大,右半部分都比它大
    	quicksort(nums, low, p - 1);//递归
    	quicksort(nums, p + 1, high);
    }
    
    //集成版的partion
    int partition1(vector<int>& nums, int low, int high) {
    	
    	uniform_int_distribution<int> u(low, high);
    	default_random_engine e;//生成无符号随机整数
    	std::swap(nums[u(e)], nums[high]);//避免最糟糕的情况出现,随机选值放到最右端
    	int i = 0, j = 0;
    	for (i = low, j = low;j < high;++j) {//从头到尾遍历每个数,但不遍历最后的基准值
    		if (nums[j] <= nums[high]) {//如果发现当前数不大于基准值
    			std::swap(nums[i++], nums[j]);//把这个不大于基准值的数与i位置上的数交换,同时i++
    		}
    	}//结束后,i之前的所有的数都不大于基准值,i之后所有的数都大于基准值;退出的时候j=high
    	std::swap(nums[i], nums[j]);//把j位置的数(基准值)换到i位置上来
    	return i;
    }
    
    //打印数组
    void printVector(const vector<int>& a) {
    	for (auto i : a) {
    		cout << i << " ";
    	}
    	cout << endl;
    }
    
    int main(int argc, char** argv) {
    	vector<int> a{ 5,6,4,2,3 };
    	quicksort(a, 0, a.size() - 1);
    	printVector(a);
    	return 0;
    }
    

    从两端逼近:

    /*靠谱的方法*/
    void quicksort1(vector<int>& nums, int left, int right) {
    
    	int i = left, j = right;
    
    	if (left > right) return;//左已经跑到右了
    
    	int target = nums[left];//以最左边的数为基准
    	while (i < j) {
    		while (nums[j] >= target && i < j) {//为了找到小于基准的数,就要略过不小于基准的数们
    			j--;
    		}
    
    		while (nums[i] <= target && i < j) {//为了找到大于基准的数,就要略过不大于基准的数们
    			i++;
    		}
    
    		if (i < j) {
    			swap(nums[i], nums[j]);//一次交换两个数
    		}
    	}
    	nums[left] = nums[i];
    	nums[i] = target;
    
    	quicksort1(nums, left, i - 1);
    	quicksort1(nums, i + 1, right);
    	return;
    }
    
  • 相关阅读:
    注释
    选择器
    SQL语句中查找字符的位置
    SQL语句中截取字符串Substr
    IDENTITY(函数)
    SQL Server设置主键自增长列
    SQL语句操作ALTER
    表的主键
    南京夜市
    夜班
  • 原文地址:https://www.cnblogs.com/dindin1995/p/13059104.html
Copyright © 2020-2023  润新知