c++排序算法

冒泡排序

//冒泡 通过多次交换相邻元素将较大(或较小)的元素逐渐 "浮" 到数组的一端。该算法的时间复杂度为 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]);
			}
		}
	}
}

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

选择排序

//选择排序 在每次迭代中选择未排序部分的最小(或最大)元素,并将其放在已排序部分的末尾。时间复杂度为 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]);
	}
}

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

插入排序

//插入排序  将未排序部分的元素逐个插入到已排序部分的正确位置。时间复杂度为 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;
	}
}

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

快速排序

//快速排序(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相等,此次,基枢位置确定,把最开始设置的基枢赋值过来。基枢位置确定之后,就有了左右分区。在左右分区继续快排。

归并排序

//归并排序
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 中。最后,将临时数组中的元素复制回原数组。

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 是数据的范围。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值