堆排序&快速排序(C语言)

算法设计与分析

这门课程里会用到好多以前学到的算法!可是都被我遗忘了...

所以我来浅浅记录一下,那些曾经在我脑子里住过一段时间的代码们!


目录

堆排序

快速排序


堆排序

堆是一种经过排序的完全二叉树

基本思想:

  • 需要调整堆、堆排序(调用调整堆函数)两个函数
  • 考虑原数组下标,最小下标为0或1的两种情况会导致结点左孩子的下标关系不同(下方有举例),一定要明确这个点,在主函数中如for循环的取值会有不同
  • 将数组转换为完全二叉树后,需要调整堆使其变为大根堆或小根堆
  • 排序时是将根结点的数(即数组中第一个数,假设为num【0】)与堆(数组)中未确定位置的最后一个数(假设为num【i】)进行交换
  • 这时,就确定了被换到最后一位的数(根据大根堆和小根堆的概念,这个数一定是最大或最小的数)的位置(下标,i),再对num【i】之前的结点进行调整
  • 若要得到升序数组,则开始要构建大根堆;若要得到降序数组,则开始要构建小根堆

最小下标为0

void heapadjust(int* num, int len, int i) {
/*
num是数组
len是数组大小(下同)
i是将要调整的结点(数组下标)
*/
	int key = num[i];

	for (int j = i * 2 + 1; j < len; j = j * 2 + 1) {   //最小下标为0和1的第一个区别点

		if (j<len - 1 && num[j] > num[j + 1])
			j++;

		if (num[j] < key) {
			num[i] = num[j];
			i = j;
		}
	}

	num[i] = key;
}

void heapsort(int* num, int len) {
	for (int j = len / 2 - 1; j >= 0; j--) {   //最小下标为0和1的第二个区别点
		heapadjust(num, len, j);
	}

	for (int i = len - 1; i > 0; i--) {   //最小下标为0和1的第三个区别点

		int temp = num[i];
		num[i] = num[0];
		num[0] = temp;
		heapadjust(num, i, 0);

	}
}

最小下标为1

void heapadjust(int* num, int len, int i) {

	int j;
	int tmp = num[i];

	for (j = 2 * i; j <= len; j *= 2) {

		if (j < len&& num[j] < num[j + 1]) {
			j++;
		}

		if (num[j] > tmp) {
			num[i] = num[j];
			i = j;
		}
	}

	num[i] = tmp;
}

void heapsort(int* num, int len) {

	for (int i = len / 2; i > 0; i--) {
		heapadjust(num, len, i);
	}

	for (int i = len; i > 0; i--) {
		int tmp = num[i];
		num[i] = num[1];
		num[1] = tmp;
		heapadjust(num, i - 1, 1);
	}
}

主函数中,再根据要求调用heapsort函数即可完成堆排序。

堆排序的基本思路:❗堆排序❗基本思路 学习记录 防止遗忘 浅浅记录一下~_哔哩哔哩_bilibili-https://b23.tv/KwsQ18W


快速排序

相较于堆排序,快速排序的算法思路简单一些:

  • 随机取数组中的一个数(默认选择第一个数),将它作为key
  • 取两个标记位ij,分别从key后面一个数最后一个数开始遍历
  • 先取j从最后一个数开始遍历,若num【j】>=key,则j--;若num【j】<key,则将num【j】放入原先key的位置,此时,num【j】处的位置空出来了,结束循环
  • 再取i从原先key位置的后一个位置开始遍历,若num【i】<=key,则i++;若num【i】>key,则将num【i】放入上述空位置中,结束循环
  • 重复i和j的遍历直到i=j,将key放入最后一个空位置中
  • 一次遍历之后得到数组,可以发现key左边都是小于key的数,key右边都是大于key的数
  • key左右两边(还未有序)再次调用本函数,直到全部排序完毕
void sort(int* num, int low, int high) {

	if (low > high) return;
	int i = low;
	int j = high;
	int key = num[low];

	while (i < j) {
		while (i<j && num[j]>=key) {
			j--;
		}

		num[i] = num[j];

		while (i < j && num[i] <= key) {
			i++;
		}

		num[j] = num[i];
	}

	num[i] = key;
	sort(num, low, i - 1);  //快排key左边的数
	sort(num, i + 1, high);  //快排key右边的数
}

主函数中,再根据要求调用sort函数即可完成快速排序。

快速排序还有很多衍生的相似算法,如解决将所有奇数排到偶数左边的问题时,可借鉴快速排序算法;如解决寻找数组中最小k的数的问题,可采用线性选择算法,是快速排序的一种优化。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值