c++排序算法

冒泡排序

cpp 复制代码
//冒泡 通过多次交换相邻元素将较大(或较小)的元素逐渐 "浮" 到数组的一端。该算法的时间复杂度为 O(N^2)。
void bubbleSort(vector<int>&arr) {
	int n=arr.size();
	for(int i=0; i<n-1; i++) {
		for(int j=0; j<n-i-1; j++) {
			if(arr[j]>arr[j+1]) {
				swap(arr[j],arr[j+1]);
			}
		}
	}
}

两层循环,一次次比较交换。

选择排序

cpp 复制代码
//选择排序 在每次迭代中选择未排序部分的最小(或最大)元素,并将其放在已排序部分的末尾。时间复杂度为 O(N^2)。

void selectionSort(std::vector<int>& arr) {
	int n = arr.size();
	for(int i=0; i<n; i++) {
		int minIndex=i;
		for(int j=i+1; j<n; j++) { //找未排序部分的最小值对应的index
			if(arr[j]<arr[minIndex]) {
				minIndex=j;
			}
		}
		//找到未排序部分的最小值之后,需要放在有序部分的末尾,也就是i位置.所以交换.
		swap(arr[i],arr[minIndex]);
	}
}

在未排序部分选一个最小的放到有序部分末尾。

插入排序

cpp 复制代码
//插入排序  将未排序部分的元素逐个插入到已排序部分的正确位置。时间复杂度为 O(N^2),但对于小型数据集或部分已排序的数据,插入排序具有较好的性能。
void insertionSort(std::vector<int>& arr) {
	int n = arr.size();
	for (int i = 1; i < n; ++i) {
		int key = arr[i];
		int j = i - 1;
		while (j >= 0 && arr[j] > key) {
			arr[j + 1] = arr[j];
			--j;
		}
		arr[j+1]=key;
	}
}

从未排序部分取一个插入到有序部分。

快速排序

cpp 复制代码
//快速排序(Quick Sort):也是采用分治策略的排序算法,通过选择一个基准值,将数据分为小于基准值和大于基准值的两部分,然后递归地对这两部分进行排序。时间复杂度为 O(NlogN),具有较好的性能。
// 将数组以升序进行排列!
// 分区操作函数,将数组分成两个部分并返回基准元素的最终位置
void quickSort(vector<int> &nums, int l, int r) {
	if (l + 1 >= r) {
		return;
	}
	int first = l, last = r - 1, key = nums[first];
	while (first < last) {
		while(first < last && nums[last] > key) {
			--last;
		}//从右往左找小于基枢的值
		nums[first] = nums[last];
		//把小于基枢的值赋给左边.
		while (first < last && nums[first] < key) {
			++first;
		}//从左往右找大于基枢的值
		nums[last] = nums[first]; //找到之后把这个大于基枢的值再赋给右边.
	}//这样循环下去,first指向的位置最终左边都是小于基枢,右边都是大于基枢. first=last把基枢位置确定下来.
	nums[first] = key;
	quickSort(nums, l, first);
	quickSort(nums, first + 1, r);
}

分支法,先分区,找到分区的位置后,两边继续

quickSort(nums, l, first);

quickSort(nums, first + 1, r);

首先设置第一个为基枢。从右往左找比基枢小的值,然后复制到first,接着从first向右找第一个比基枢大的值,复制到fast位置,然后fast往左找小的,再给first赋值,直到first和last相等,此次,基枢位置确定,把最开始设置的基枢赋值过来。基枢位置确定之后,就有了左右分区。在左右分区继续快排。

归并排序

cpp 复制代码
//归并排序
void merge_sort(vector<int> &nums, int l, int r, vector<int> &temp) {
	if (l + 1 >= r) {
		return;
	}
// divide
	int m = l + (r - l) / 2;
	merge_sort(nums, l, m, temp);

	merge_sort(nums, m, r, temp);
// conquer
	int p = l, q = m, i = l;
	while (p < m || q < r) {
		if (q >= r || (p < m && nums[p] <= nums[q])) {
			temp[i++] = nums[p++];
		} else {
			temp[i++] = nums[q++];
		}
	}
	for (i = l; i < r; ++i) {
		nums[i] = temp[i];
	}
}

在合并过程中,我们使用双指针 pq 分别指向左右两个子数组的起始位置,然后比较指针位置处的元素大小,将较小的元素放入临时数组 temp 中。最后,将临时数组中的元素复制回原数组。

cpp 复制代码
int main() {
	std::vector<int> numbers = {5, 2, 8, 1, 3};

//	std::sort(numbers.begin(), numbers.end());
	//快排 std::sort:使用快速排序(Quick Sort)实现的排序算法,平均时间复杂度为 O(NlogN)
//	std::stable_sort(numbers.begin(), numbers.end());
	//std::stable_sort:使用归并排序(Merge Sort)实现的排序算法,保持相等元素的相对顺序。时间复杂度为 O(NlogN)
//	bubbleSort(numbers);//冒泡排序的平均时间复杂度为 O(N^2)
//	selectionSort(numbers);//选择排序的时间复杂度为 O(N^2)
//    insertionSort(numbers);//插入排序的时间复杂度为 O(N^2)
//	quickSort(numbers,0,numbers.size());
	vector<int> temp(numbers.size());
	merge_sort(numbers, 0, numbers.size(), temp);


	std::cout << "Sorted numbers: ";
	for (int num : numbers) {
		std::cout << num << " ";
	}
	std::cout << std::endl;

	return 0;
}

是否稳定

  1. 稳定的排序算法

    • 冒泡排序(Bubble Sort)
    • 插入排序(Insertion Sort)
    • 归并排序(Merge Sort)
    • 基数排序(Radix Sort)
  2. 不稳定的排序算法

    • 选择排序(Selection Sort)
    • 快速排序(Quick Sort)
    • 堆排序(Heap Sort)
    • 希尔排序(Shell Sort)

时间复杂度

  • 冒泡排序、插入排序、选择排序的时间复杂度为 O(n^2)。
  • 归并排序、快速排序、堆排序的平均时间复杂度为 O(n log n)。
  • 基数排序的时间复杂度为 O(d * (n + k))

空间复杂度

空间复杂度是指算法在运行过程中所需要的额外的存储空间大小。以下是几种常见排序算法的空间复杂度:

  1. 冒泡排序(Bubble Sort):空间复杂度为 O(1),因为只需要常数级别的额外空间用于交换元素。

  2. 插入排序(Insertion Sort):空间复杂度为 O(1),因为只需要常数级别的额外空间用于交换元素。

  3. 选择排序(Selection Sort):空间复杂度为 O(1),因为只需要常数级别的额外空间用于交换元素。

  4. 归并排序(Merge Sort):归并排序是一种分治算法,在归并过程中需要额外的空间来存储临时数组,所以空间复杂度为 O(n)。

  5. 快速排序(Quick Sort):快速排序是一种原地排序算法,通常不需要额外的空间,但是如果使用递归实现,则需要系统栈来存储递归调用的上下文,因此空间复杂度在最坏情况下可能达到 O(n),平均情况下为 O(log n)。

  6. 堆排序(Heap Sort):堆排序是一种原地排序算法,不需要额外的空间,因此空间复杂度为 O(1)。

  7. 希尔排序(Shell Sort):希尔排序是一种改进的插入排序算法,空间复杂度取决于间隔序列的选择,一般为 O(1) 到 O(n)。

  8. 基数排序(Radix Sort):基数排序需要额外的空间来存储桶,空间复杂度取决于数据的范围和位数,一般为 O(n + k),其中 n 是数组长度,k 是数据的范围。

相关推荐
冠位观测者1 分钟前
【Leetcode 每日一题】2545. 根据第 K 场考试的分数排序
数据结构·算法·leetcode
轩辰~7 分钟前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
lxyzcm27 分钟前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
蜀黍@猿1 小时前
C/C++基础错题归纳
c++
古希腊掌管学习的神1 小时前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca1 小时前
洛谷 P1706 全排列问题 C语言
算法
浊酒南街1 小时前
决策树(理论知识1)
算法·决策树·机器学习
雨中rain1 小时前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
就爱学编程1 小时前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条1 小时前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学