C++ 十大数组排序(冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序)

一、简单总结:

1.冒泡排序:不断把大的往后移一步,排序终点随着循环往前移;

2.选择排序:维护排序起点,把最小挑出来放前面;

3.插入排序:维护排序起点,从链表起点开始找插入位置,把小的往前插;

4.希尔排序:可以理解为分组的插入排序,按增长量作为分组的依据,将一定间隔的数据分为一组进行插入排序,不断减小增长量,重复插入排序的操作,直到增长量为1;

5.归并排序:先递归对数组进行二分,直到每一组只剩一个元素(绝对有序),再进行有序数组的合并;

6.快排排序:将最左边的节点作为参照数(传统快排),双指针,右指针负责找比参照数小的节点,左指针负责不断将大于参照数的节点与快指针节点进行值交换(注意这里一定要右指针先动,否则可能遇到参照数刚好为最大元素,左指针一直找不到大于参照数的数值,参照数没有被正确交换到数组尾部);

7.堆排序:建立一个大顶堆,不断的将堆顶的元素与数组末端的元素交换位置,关键在于维护堆性质的函数heapify C++自建堆

8.计数排序:设立一个大小为数组最大值的数组count(n),记录count[num],通过计数累计和的方式定位原数组中每个元素在排序数组的位置

9.桶排序:根据数组的值域区间设定桶数量和桶大小,将每个元素根据大小放到对应的桶上面,在桶内使用快速排序,最后合并每个排序好的桶

10.基数排序:结合了计数排序和桶排序的思想,从个位开始,按照数字的每一位进行0-9的桶排序,桶合并采用计数累计和的思想确认桶内元素合并后的位置

二、代码及注释 

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


void printArray(vector<int>&nums) {
	for (const int& num : nums) {
		cout << num << ' ';
	}
	cout << endl;
}

// 冒泡排序
void bubbleSort(vector<int>&nums) {
	int n = nums.size();
	for (int i = 0; i < n; ++i) {
		// 每次循环把最大的数换到n-i-1的位置
		for (int j = 1; j < n-i; ++j) {
			if (nums[j - 1] > nums[j]) swap(nums[j], nums[j - 1]);
		}
	}
}

// 选择排序
void selectSort(vector<int>& nums) {
	int n = nums.size();
	for (int i = 0; i < n; ++i) {
		// 每次循环从i+1 - n里面挑一个最小的数换到i
		int minN = i;
		for (int j = i+1; j < n; ++j) {
			if (nums[j] < nums[minN]) minN = j;
		}
		swap(nums[minN], nums[i]);
	}
}

// 插入排序
void insertionSort(vector<int>& nums) {
	int n = nums.size();
	// 从第二个元素开始遍历
	for (int i = 1; i < n; ++i) {
		int num = nums[i];
		int j = i - 1;
		// 每一个比第i+1个元素大的元素都会被后移,最后小的元素会被插入到前面
		while (j >= 0 && nums[j] > num) {
			swap(nums[j], nums[j + 1]);
			--j;
		}
	}
}

// 希尔排序
void shellSort(vector<int>& nums) {
	int n = nums.size();
	// 取初始区间为n/2 ,每次区间都缩小1/2
	for (int gap = n >> 1; gap > 0; gap >>= 1) {
		// 以i = 1 * gap 开始, 往后遍历,不断进行插入排序
		for (int i = gap; i < n; ++i) {
			int num = nums[i];
			// 插入排序部分,如果上一个元素比当前元素小,则将上一个元素移到前面,找到合适的插入位置
			for (int j = i - gap; j >= 0 && nums[j] > num; j -= gap) {
				swap(nums[j], nums[j + gap]);
			}
		}
	}
}

// 归并排序
void merge(vector<int>& nums, vector<int>& arr, int left, int mid, int right) {
	int i = left, j = mid + 1;
	int start = left - 1;
	while (i <= mid && j <= right) {
		arr[++start] = nums[i] < nums[j] ? nums[i++] : nums[j++];
	}
	// 合并剩余元素
	while (i <= mid) arr[++start] = nums[i++];
	while (j <= right) arr[++start] = nums[j++];
	// 赋值给原数组
	while (left <= right) {
		nums[left] = arr[left];
		++left;
	}
}
void m_sort(vector<int>& nums, vector<int>& arr, int left, int right) {
	if (left < right) {
		int mid = (left + right) >> 1;
		// 递归分组
		m_sort(nums, arr, left, mid);
		m_sort(nums, arr, mid + 1, right);
		// 最后一层递归合并
		merge(nums, arr, left, mid, right);
	}
}
void mergeSort(vector<int>& nums) {
	int n = nums.size();
	vector<int>arr(n);
	m_sort(nums, arr, 0, n - 1);
}

// 快速排序
void q_sort(vector<int>& nums, int left, int right) {
	if (left < right) {
		int i = left, j = right;
		while (i < j) {
			while (i < j && nums[j] >= nums[left]) --j;
			while (i < j && nums[i] <= nums[left]) ++i;
			swap(nums[i], nums[j]);
		}
		swap(nums[i], nums[left]);
		q_sort(nums, left, i - 1);
		q_sort(nums, i + 1, right);
	}
}
void quickSort(vector<int>& nums) {
	int n = nums.size();
	q_sort(nums, 0, n-1);
}

// 堆排序
void heapify(vector<int>& nums, int idx, int n) {
	// 左右孩子的下标
	int left = (idx << 1) + 1, right = (idx << 1) + 2;
	int largestIdx = idx;
	// 升序排序用大顶堆,因为每次能将数组首部(堆顶)最大的元素换到数组末端
	// 左右孩子下标可能越界
	if (left < n && nums[left] > nums[largestIdx]) largestIdx = left;
	if (right < n && nums[right] > nums[largestIdx]) largestIdx = right;
	// 如果左右孩子有大于父亲的数,交换位置,并继续往后维护堆结构
	if (largestIdx != idx) {
		swap(nums[largestIdx], nums[idx]);
		heapify(nums, largestIdx, n);
	}
}


void heapSort(vector<int>& nums) {
	int n = nums.size();
	// 建堆
	// 下标为i的父节点下标为(i-1)/2,下标为n-1则为n/2-1
	for (int i = n >> 1 - 1; i >= 0; --i) {
		heapify(nums, i, n);
	}
	// 排序
	for (int i = n - 1; i > 0; --i) {
		// 将最大的堆顶元素交换到未排序数组的末端
		swap(nums[0], nums[i]);
		// 维护从堆顶到未排序数组末端的堆结构
		heapify(nums, 0, i);
	}
}

// 计数排序
void countSort(vector<int>& nums) {
	int n = nums.size();
	int maxN = *max_element(nums.begin(), nums.end());
	vector<int>count(maxN+1);
	for (const int& num : nums)++count[num];
	for (int i = 1; i <= maxN; ++i) count[i] += count[i - 1];
	vector<int>arr(n); // 临时数组,存储排序后的数值
	for (int i = n - 1; i >= 0; --i) { // 倒序遍历可以让排序稳定,原来在后面的数仍旧在后面,因为count数组是累加的
		int num = nums[i];
		arr[count[num] - 1] = num;
		--count[num];
	}
	nums.assign(arr.begin(), arr.end());
}


// 桶排序
void bucketSort(vector<int>& nums) {
	int n = nums.size();
	// 根据值域区间设置桶的数目和大小
	int bucketNum = 10, bucketSize = 10;
	vector<vector<int>>buckets(bucketNum);
	// 将数按照大小装进对应桶里
	for (const int& num : nums) {
		buckets[num / bucketSize].emplace_back(num);
	}
	// 每个桶使用快排
	for (auto& bucket : buckets) {
		quickSort(bucket);
	}
	// 写回原数组
	int i = -1;
	for (auto& bucket : buckets) {
		for (int& num : bucket) {
			nums[++i] = num;
		}
	}
}

// 基数排序
void rdx_sort(vector<int>& nums, int exp) {
	int n = nums.size();
	vector<int>arr(n);
	// 0-9十个桶
	vector<int>bucket(10);
	// 每一位都采用桶排序的思想装入桶中
	for (const int& num : nums) {
		++bucket[(num / exp) % 10];
	}
	// 采用计数排序的思想合并序列
	for (int i = 1; i < 10; ++i) bucket[i] += bucket[i - 1];
	for (int i = n - 1; i >= 0; --i) {
		int num = (nums[i] / exp) % 10;
		arr[bucket[num]-1] = nums[i];
		--bucket[num];
	}
	nums.assign(arr.begin(), arr.end());
}

void radixSort(vector<int>& nums) {
	int maxN = *max_element(nums.begin(), nums.end());
	// 对每一位进行非比较的桶排序
	for (int i = 1; i <= maxN; i *= 10) {
		rdx_sort(nums, i);
	}
}


int main() {
	srand((unsigned)time(NULL));
	vector<int>nums(10);
	for (int i = 0; i < 10; ++i) {
		nums[i] = rand() % 100;
	}
	printArray(nums);
	//bubbleSort(nums);
	//selectSort(nums);
	//mergeSort(nums);
	//quickSort(nums);
	//insertionSort(nums);
	//shellSort(nums);
	//heapSort(nums);
	//countSort(nums);
	//bucketSort(nums);
	//radixSort(nums);
	printArray(nums);
	return 0;
}

作笔记使用,如有错误还请指正!!如果觉得有帮助可以点个赞哈哈哈!!多谢!!!溜了溜了~