算法导论学习笔记三——堆排序,快速排序

算法导论学习笔记三——堆排序,快速排序

本文是机械工业出版社出版的《算法导论(原书第三版)》的学习笔记的第三篇,对应原书第6,7章——堆排序,快速排序

算法1.堆排序
堆的基本概念:
如下图,堆可以看成一个数组,可以看成一个近似的完全二叉树,对于一个节点i,其父节点为flor(i/2),其左孩子为2i,右孩子为2i+1。
在这里插入图片描述
最大堆与最小堆:
最大堆的性质为除了根节点之外,所有节点都满足:
A [ p a r e n t ( i ) ] ≥ A [ i ] A[parent(i)] \ge A[i] A[parent(i)]A[i]
最小堆同理
堆排序:
初始时候,堆排序算法利用build_max_heap将输入数组A[1,2,…,n]建成最大堆。因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的位置。 这时候,如果我们从堆中去掉结点n,剩余的结点中,原来根的孩子结点仍然是最大堆,而新的根结点可能会违背最大堆的性质。 为了维护最大堆的性质,我们要做的是调用max_heapify(A,1) , 从而在A[1,2,…,n-1]上构造一个新的最大堆。堆排序算法会不断重复这一过程,直到堆的大小从n —1 降
到 2。
算法时间复杂度为O(nlogn)
代码:

void heapsort(int* arr, int n)
{
	build_max_heap(arr, n);//先构建一个最大堆
	int heap_size = n;
	for (int i = n - 1; i > 0; i--)
	{
		swap(&arr[i], &arr[0]);//将最大堆的根节点一定是堆中最大的节点,将其放到堆最后面
		heap_size--;//堆的长度减一
		max_heapify(arr, heap_size, 0);
		
	}
}

void build_max_heap(int* arr,int n)
{
	//创建最大堆
	//这里floor(n / 2) - 1之后的节点都是叶子节点,所以从这里往前开始即可
	for (int j = floor(n / 2) - 1; j >= 0; j--)
	{
		max_heapify(arr, n, j);
	}
}

void max_heapify(int* arr, int n, int i)
{
	//维护最大堆的性质
	//假设i的左孩子与右孩子都已经是最大堆,那么只要
	//比较当前节点与左右孩子的大小,将当前节点与较大
	//的孩子交换即可。但是这样会破坏子节点的最大堆性质,
	//所以需要递归的计算。
	int left, right,idx=i;
	left = floor(2*i+1);
	right = floor(2 * i + 2);
	if (left < n - 1 && arr[left]>arr[i])
	{
		swap(&arr[left], &arr[i]);
		idx = left;
	}
	if (right < n - 1 && arr[right]>arr[i])
	{
		swap(&arr[right], &arr[i]);
		idx = right;
	}
	if (idx != i)
	{
		max_heapify(arr, n, idx);
	}	

算法2.快速排序
算法思想
快速排序也是一种分治算法,把一个A[p,…,r]的数组划分为A[p,…,q-1],A[q]和A[q+1,…,r],使得A[p,…,q-1]<=A[q]<=A[q+1,…,r],之后再递归对A[p,…,q-1]和A[q+1,…,r]排序。
核心在于A[p,…,q-1],A[q]和A[q+1,…,r]的划分方法:
首先我们把A[r]看成主元,将A[p,…,r-1]中所有元素都跟其比较,使用两个指针i和j,A[p,…,i]存储小于主元的元素,A[i+1,…,j]存储大于主元的元素,具体见下图:
在这里插入图片描述
代码

void quicksort(int* arr, int n, int p, int r)
{
	if (p < r)
	{
		int q = patition(arr, n, p, r);
		std::cout << q<<std::endl;
		quicksort(arr, n, p, q-1);
		quicksort(arr, n, q+1, r);
	}
}
int patition(int* arr, int n, int p, int r)
{
	int x = arr[r];//主元
	int i = p - 1;
	for (int j = p; j < r; j++)
	{
		if (arr[j] <= x)
		{
			i = i + 1;
			swap(&arr[i], &arr[j]);
		}
	}
	swap(&arr[i + 1], &arr[r]);
	return i + 1;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值