C++十大排序算法学习笔记(三)

承接上一篇文章:C++十大排序学习笔记(二)_王必能会的博客-CSDN博客

一、快速排序

快速排序的基本思想原理分为以下三步:

1)先从数列中随机的取出一个数作为基准数,将其与最右边的数做交换(随机的取数,可以适当的降低时间复杂度);

2)扫描数列,将比基准数小的元素全部放在左边,等于基准数的元素放在中间,大于基准数的元素放在右边(注意:此时数列最右边的数是基准数,但是划分区间即小于, 等于, 大于时,暂不包括基准数。)区间分完后,再将基准数与大于区间的第一个数(有时也可以是等于区间的最后一个数的下一个数)做交换

3)然后再对小于区间和大于区间重复进行第一二步操作,直到各个区间少于两个元素,此时整个数组也就变成了有序数组。

代码如下:

#include <iostream>
using namespace std;
#include <vector>
#include<algorithm>
#include <math.h>
#include<cstdio>
#include<ctime>  //要调用time(),需要加入头文件< ctime >

#define random_int_3(a,b)       ((rand()%(b-a+1))+ a)            //取得[a,b]的随机整数

void print(vector<int>& arr) {
	for (int i = 0; i < arr.size(); i++) {
		cout << arr[i] << endl;
	}
}

//这是一个处理arr数组的函数    {3,5,6,7,4,3,5,8}
//默认以arr[r]做划分  划分为 <p     ==p     >p   以最右边的数作为划分值
//返回的是等于区域的左右边界,并且返回的必定是一个长度为2的数组res, 左res[0]  右res[1]
vector<int> partition(vector<int>& arr, int i, int right) {
	int less = i-1;         //小于区域的右边界
	int more = right;     //大于区域的左边界
	while (i < more) {
		if (arr[i] < arr[right]) {
			swap(arr[i], arr[++less]);
			i++;
		}
		else if (arr[i] > arr[right]) {
			swap(arr[i], arr[--more]);
		}
		else {
			i++;
		}
	}
	swap(arr[more], arr[right]);
	return { less+1, more };
}

void quickSort(vector<int> &arr, int left, int right) {
	if (left < right) {
		srand((int)time(0));  //利用系统时钟,产生不同的随机数种子,把0换成NULL也行
		int r = random_int_3(left, right);
		//int r = (rand() % (right - left + 1))+left;
		swap(arr[r], arr[right]);
		vector<int> res = partition(arr, left, right);
		quickSort(arr, left, res[0]-1);
		quickSort(arr, res[1]+1, right);
	}
}
int main() {
	vector<int> arr1 = {3,5,6,7,8,4,3,5,6,2,1,4};
    quickSort(arr1, 0, arr1.size() - 1);
    print(arr1);
    return 0;
}

二、堆排序

堆排序是利用堆这种数据结构而设计的一种排序算法,堆具备以下特点:

1) 完全二叉树;(从上到下,从左到右,每一层的节点都是满的,最下一层所有节点都连续集中在最左边。)

2)二叉树每个结点的值都大于或等于其左右子孩子的值,这是大根堆;

     或者每个结点的值都小于或等于其左右孩子结点的值,这是小根堆。

基本思想:

1. 先将已有的数组,形成一个大根堆,此时数组中最大的数必然是堆顶的元素,

2. 将堆中的最后一个元素和堆顶元素做交换,然后新的堆顶元素向下做调整,比较父节点是否比其子节点小,小的话,交换位置,向下调整。调整完毕之后,此时堆顶为除堆中最后一个元素之外的,最大的元素。需要一个辅助heapsize,每次调整完后减一

3. 重复上边操作,直到heapsize =0 ,数组变得有序。

代码如下:

#include <iostream>
using namespace std;
#include <vector>
#include<algorithm>
#include <math.h>

void print(vector<int>& arr) {
	for (int i = 0; i < arr.size(); i++) {
		cout << arr[i] << endl;
	}
}
//1、 给一个数,将数插入,形成大根堆    (某个数处在index位置,往上继续移动)
void heapInsert(vector<int>& arr, int index) {
	while (arr[index] > arr[(index - 1) / 2]) {
		swap(arr[index], arr[(index - 1) / 2]);
		index = (index - 1) / 2; 
	}
}
//2、 向下做调整 比较父节点是否比子节点小,小的话,往下走
void heapify(vector<int>& arr, int index, int heapSize) {
	int left = 2 * index + 1;
	while (left < heapSize) {
		//比较左孩子和右孩子 ,哪个数比较大,将大的数的下标给largest
		int largest = left + 1 < heapSize && arr[left+1] > arr[left] ? left+1 : left;
		//int largest = left + 1 < heapSize && arr[left] >= arr[left+1] ? left : left+1;   //就不对???
		//比较父节点和最大孩子的大小  将大的给largest
		largest = arr[largest] > arr[index] ? largest : index;

		if (largest == index) {
			break;
		}
		//将最大的数和父节点的数交换
		swap(arr[largest], arr[index]);
		index = largest;
		left = index * 2 + 1;
	}
}

//3、 进行堆排序
void heapSort(vector<int>& arr) {
	//int heapSize = arr.size();
	if (arr.size() < 2) return;
	//该操作形成一个大根堆
	for (int i = 0; i < arr.size(); i++) {
		heapInsert(arr, i);
	}
	print1(arr);
	//将最后一个数和第一个根节点做交换
	int heapSize = arr.size();
	heapSize--;
	swap(arr[0], arr[heapSize]);
	

	while (heapSize > 0) {
		print1(arr);
		heapify(arr, 0, heapSize);
		heapSize--;
		swap(arr[0], arr[heapSize]);
	}
}
int main() {
	vector<int> arr1 = {3,5,6,7,8,4,3,5,6,2,1,4};
	heapSort(arr1);
	print(arr1); 
	return 0;
}  

三、计数排序

计数排序是一种非比较排序,常用于规模大,数字种类小的排序中,如考试成绩排名、人口年龄等等。思路很简单,但实现起来不容易,首先得定义两个数组,一个用于存放数字种类的个数,另一个用于存放排好序的数组。然后遍历整个数组,记录下数组中各数字的个数存放于第一个数组中,比如1出现一次,就存放于temp[arr[1]]中,然后再将这些出现的个数一次存放在新的数组中,从而达到排好序。

代码如下:

#include <iostream>
using namespace std;
#include <vector>

void countsort(vector<int>& arr) {
	int n = arr.size();
	vector<int> temp(1024), result(1024);
	for (int i = 0; i < n; i++) {
		temp[arr[i]]++;
	}
	for (int i = 0; i < n; i++) {
		temp[i + 1] += temp[i];
	}
	for (int i = n - 1; i >= 0; i--) {
		result[--temp[arr[i]]] = arr[i];
	}
	for (int i = 0; i < n; i++)//打印数组
	{
		cout << result[i] << " ";
	}
}
int main(){
    vector<int> arr = {3,7,1,5,2,9,3,8,4};
    countsort(arr);
    return 0;
}

四、基数排序

基数排序和计数排序原理差不多,但是适用范围更大一些。 

#include <iostream>
using namespace std;
#include <vector>
#include <math.h>

void print(vector<int>& arr) {
	for (int i = 0; i < arr.size(); i++) {
		cout << arr[i] << endl;
	}
}

int getDigit(int x, int d) {
	int res = (x / (int)pow(10, d - 1)) % 10;
	return res;
}

int maxbits(vector<int>& arr) {
	int max1 = INT_MIN;
	for (int i = 0; i < arr.size(); i++) {
		max1 = max(max1, arr[i]);
	}
	int res = 0;
	while (max1 != 0) {
		res++;
		max1 /= 10;
	}
	return res;
}
//digit 输入参数,事先应该确定数组中最大的数为多少位 
void radixSort(vector<int>& arr, int L, int R, int digit) {
	const int radix = 10;
	int i = 0;
	int j = 0;
	vector<int> bucket;
	//int m = R - L + 1;
	bucket.resize(R - L + 1);
	for (int d = 1; d <= digit; d++){
		vector<int> count;
		count.resize(radix);
		for (i = L; i <= R; i++) {
			j = getDigit(arr[i], d);
			count[j]++;
		}
		for (i = 1; i < radix; i++ ){
			count[i] = count[i] + count[i - 1];
		}
		for (i = R; i >= L; i--) {
			j = getDigit(arr[i], d);
			bucket[count[j] - 1] = arr[i]; 
			count[j]--;
		}
		for (i = L, j = 0; i <= R; i++, j++) {
			arr[i] = bucket[j];
		}
	}
}
int main(){
    vector<int> arr = { 9, 5, 8, 2, 10, 3, 6, 18 ,4};
    int  m = maxbits(arr);
	radixSort(arr, 0, arr.size() - 1,m);
	print(arr); 
    return 0;
}

五、桶排序

桶排序的原理: 假设输入数据服从均匀分布,将数据分到有限数量的桶里,然后对每个桶分别排序(每个桶里数据排序可以选用上边的九种排序方法的任意一种),最后把全部桶的数据合并。

代码如下:对没有0元素的数组排序;且每个桶中元素的数量不超过5;

//假设每个桶中元素的数量不超过5;
void bucketsort(vector<int>& arr) {
	int n = arr.size();
	vector<vector<int>> bucket(5,vector<int>(5,0));
	cout << "bucket二维数组初始化后为:" << endl;
	for (int i = 0; i < bucket.size(); i++) {
		for (int j = 0; j < bucket[0].size(); j++) {
			cout << bucket[i][j] << "  ";
		}
		cout << endl;
	}
	vector<int> bucketsize(5);//每个桶的计数器

	for (int i = 0; i < n; i++) {
		int m = arr[i] / 10;
		bucket[m][bucketsize[m]++] = arr[i];
	}
	for (int i = 0; i < 5; i++) {
		bubblesort1(bucket[i]);
	}
	cout << "排序完成之后各个桶的数据:" << endl;
	for (int i = 0; i < bucket.size(); i++) {
		for (int j = 0; j < bucket[0].size(); j++) {
			cout << bucket[i][j] << "  ";
		}
		cout << endl;
	}
	int k = 0;
	cout << "排序后的arr数组变为:" << endl;
	for (int i = 0; i < bucket.size(); i++) {
		for (int j = 0; j < bucketsize[0].size(); j++) {
			if (bucket[i][j] != 0) {
				arr[k++] = bucket[i][j];
			}
		}
	}
}
int main() {
	vector<int> arr = {19,25,38,2,10,18,4};
	bucketsort(arr);
	print(arr);
	return 0;
}  

运行结果如下图:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值