堆与堆排序

记得看注释

big small Heap.h

#pragma once
#include 
#include 
//先构造大堆
#include 
#include 

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;
int c = 7;
int* s = &c;
//向上调整算法
void AdjustUp(HPDataType* Up, int child);//我们得知道插入的位置在哪我们才能调整
//需要自定义一个向上调整算法
//向上调整算法可以建堆
void AdjustUp(HPDataType* Up, int child)//跟老师的思路一样,没问题
{
	int tmp = 0;
	int parents = (child - 1) / 2;//这样插入的前提是本身他就是个堆我们才能这么插入
	while (child)
	{
		parents = (child - 1) / 2;
		if (Up[parents] < Up[child])
		{
			tmp = Up[child];
			Up[child] = Up[parents];
			Up[parents] = tmp;
			child = parents;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(HPDataType* a, int n, int parents);//向下调整算法,可以用于删除数据
//因为我们删除数据的原理是队头数据和队尾部数据交换,然后队尾-1
//再开始执行向下调整算法(那此时这里我们有几个要注意的点就是——我们如果直接删除队头数据的话
//我们可能会打乱堆里面的整体数据顺序,而为了不打乱整体的数据顺序,所以我们
//采用交换位置的方法),然后执行向下调整算法
void AdjustDown(HPDataType* a, int n, int parents)
{
	//向下调整算法里我们得知道他的父节点,再开始进行向下调整
	//而在向下调整的时候,我们得判断两边哪个最大,我们挑最大的上场,然后在他的路径下一直判断
	//挑最大的上来能保证第一行是最大的
	//因为根据我们的前面的推论左右孩子永远比父节点小
	//所以我们如果交换后是最小的我们就把他放到左子树或右子树(放在左子树和右子树取决与第一次判断)的最下面
	//这里我们不用定义leftchild和rightchild,而是我们
	//用一种很独特的方式
	//假设定义法,我们直接去把定义一个孩子定义为最大的
	//已知左孩子公式为 2*parents+1
	//这里我们假设左孩子为最大
	int tmp = 0;//交换的容器
	int child = 2 * parents + 1;
	while (child  < n)//迭代过程,停止条件,也不能child-1 a[child+1] && child+1 a[child])
		{
			tmp = a[parents];
			a[parents] = a[child];
			a[child] = tmp;
			parents = child;
			child = 2 * parents + 1;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown1(HPDataType* a, int n, int parents);//向下调整算法,可以用于删除数据
//因为我们删除数据的原理是队头数据和队尾部数据交换,然后队尾-1
//再开始执行向下调整算法(那此时这里我们有几个要注意的点就是——我们如果直接删除队头数据的话
//我们可能会打乱堆里面的整体数据顺序,而为了不打乱整体的数据顺序,所以我们
//采用交换位置的方法),然后执行向下调整算法
void AdjustDown1(HPDataType* a, int n, int parents)//调整数组里的值,小根堆
{
	//向下调整算法里我们得知道他的父节点,再开始进行向下调整
	//而在向下调整的时候,我们得判断两边哪个最大,我们挑最大的上场,然后在他的路径下一直判断
	//挑最大的上来能保证第一行是最大的
	//因为根据我们的前面的推论左右孩子永远比父节点小
	//所以我们如果交换后是最小的我们就把他放到左子树或右子树(放在左子树和右子树取决与第一次判断)的最下面
	//这里我们不用定义leftchild和rightchild,而是我们
	//用一种很独特的方式
	//假设定义法,我们直接去把定义一个孩子定义为最大的
	//已知左孩子公式为 2*parents+1
	//这里我们假设左孩子为最大
	int tmp = 0;//交换的容器
	int child = 2 * parents + 2;
	while (child-1 < n)//迭代过程,停止条件
	{
		if (a[child] > a[child-1])//先判断左右孩子哪个大,如果假设的孩子小,那么就++下标
			//其实就是左孩子小于右孩子,那么下标就跳到右孩子这里
		{
			child--;
		}

		if (a[parents] < a[child])
		{

			break;
		}
		else
		{
			tmp = a[parents];
			a[parents] = a[child];
			a[child] = tmp;
			parents = child;
			child = 2 * parents + 1;
		}
	}
}


// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	hp->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	hp->_capacity = n;
	hp->_size = n;
	if (hp->_a == NULL)
	{
		perror("malloc fail\n");
		exit(-1);
	}
	int i = 0;
	//while (i= 0; --i)//修改数组的值,我们利用堆进行
	{
		AdjustDown(a, n, i);
	}
	memcpy(hp->_a, a, sizeof(HPDataType) * n);//用内存函数去把数组这些里面的内存拷贝到hp_a
	// 建堆算法
}

void swap(Heap* hp);//删除的时候为了不改变顺序而交换
void swap(Heap* hp)
{
	assert(hp);
	assert(hp->_size > 0);
	int tmp = 0;
	tmp = hp->_a[0];
	hp->_a[0] = hp->_a[hp->_size - 1]; 
	hp->_a[hp->_size - 1] = tmp;
	return;
}

// 堆的销毁
void HeapDestory(Heap* hp);
void HeapDestory(Heap* hp)
{
	hp->_size = hp->_capacity = 0;
	free(hp->_a);
	free(hp);
}

// 堆的插入
//我们把堆看成一个完全二叉树,每次的插入必定有一个父节点
//1.所以我们可以根据堆的父节点公式推出父节点,并且我们现在实现的是大堆,所以每次插入时要去比对
//堆的插入是
void HeapPush(Heap* hp, HPDataType x);
void HeapPush(Heap* hp, HPDataType x)//这里我们只需要调整一条祖先路径就行
//我们的堆不是栈,我们的堆只要确保他的父节点比他的孩子节点大就行//没问题
{
	//第一种方法
	if (hp->_capacity == hp->_size)
	{
		++hp->_capacity;
		HPDataType* ptr = (HPDataType*)realloc(hp->_a, sizeof(HPDataType) * hp->_capacity);
		if (ptr == NULL)
		{
			perror(" malloc fail ");
			exit(-1);
		}
		hp->_a = ptr;
	}
	int child = hp->_size;
	hp->_a[hp->_size++] = x;
	AdjustUp(hp->_a,child);
}



// 堆的删除
void HeapPop(Heap* hp);//删除之后要维持这个大根堆
//堆的删除要注意,是因为我们如果直接删除堆顶的话
//那么我们可能就会所有节点的顺序就会变了
//所以堆的删除我们可以最后一个和第一个互换位置
//然后size--,我们在看看交换后是不是比他左右孩子大
//如果不是就挑最大的上来,挑最大的上来能保证第一行是最大的
//因为根据我们的前面的推论左右孩子永远比父节点小
//所以我们如果交换后是最小的我们就把他放到左子树或右子树(放在左子树和右子树取决与第一次判断)的最下面
void HeapPop(Heap* hp)
{
    assert(hp);
	assert(hp->_size > 0);
	swap(hp);
	//此时是我们已知父亲节点
	//求孩子节点
	//求孩子节点的公式就是
	//int child = 0;
	//int parents = 0;
	//int tmp = 0;
	//int leftchild = 2 * parents + 1;
	//int rightchild = 2 * parents + 2;
	//while ((leftchild = 2 * parents + 1) < hp->_size - 1 && (rightchild = 2 * parents + 2) < hp->_size - 1)//想一想我们应该以什么截止呢,是child还是parents
	//{
	//	/*leftchild = 2 * parents + 1;
	//	rightchild = 2 * parents + 2;*/
	//	if (hp->_a[parents] >= hp->_a[rightchild] && hp->_a[parents] < hp->_a[leftchild])
	//	{
	//		tmp = hp->_a[leftchild];
	//		hp->_a[leftchild] = hp->_a[parents];
	//		hp->_a[parents] = tmp;
	//		parents = leftchild;
	//	}
	//	else if (hp->_a[parents] < hp->_a[rightchild] && hp->_a[parents] >= hp->_a[leftchild])
	//	{
	//		tmp = hp->_a[rightchild];
	//		hp->_a[rightchild] = hp->_a[parents];
	//		hp->_a[parents] = tmp;
	//		parents = rightchild;
	//	}
	//	else if (hp->_a[parents] < hp->_a[rightchild] && hp->_a[parents] < hp->_a[leftchild])
	//	{
	//		if (hp->_a[rightchild] >= hp->_a[leftchild])
	//		{
	//			tmp = hp->_a[rightchild];
	//			hp->_a[rightchild] = hp->_a[parents];
	//			hp->_a[parents] = tmp;
	//			parents = rightchild;
	//		}
	//		else
	//		{
	//			tmp = hp->_a[leftchild];
	//			hp->_a[leftchild] = hp->_a[parents];
	//			hp->_a[parents] = tmp;
	//			parents = leftchild;
	//		}
	//	}
	//	else
	//	{
	//		break;
	//	}
	//}
	hp->_size--;
	int parents = 0;
	AdjustDown(hp->_a, hp->_size, parents);
}
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(hp->_size > 0);
	return hp->_a[0];
}
// 堆的数据个数
int HeapSize(Heap* hp);
int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}
// 堆的判空
int HeapEmpty(Heap* hp);
int HeapEmpty(Heap* hp)
{
	assert(hp);
	return hp->_size == 0;
}
void Print(Heap* h1);
void Print(Heap* h1)
{
	for (int i=0;i_size;i++)
	{
		printf("%d ", h1->_a[i]);
	}
	printf("\n");
}
// TopK问题:找出N个数里面最大/最小的前K个问题。
// 比如:未央区排名前10的泡馍,西安交通大学王者荣耀排名前10的韩信,全国排名前10的李白。等等问题都是Topk问题,
// 需要注意:
// 找最大的前K个,建立K个数的小堆
// 找最小的前K个,建立K个数的大堆

//我这里是大根堆,所以我们第一个父节点永远是最大的
//可能左节点的孩子比右节点大,可能右节点的孩子比左节点大,但是他们都比自身的父节点小
//他们的父节点又比自身的父节点小,所以层层从下往上推,第一个父节点肯定是最大的
void PrintTopK(int* a, int n, int k, Heap* h1);
void PrintTopK(int* a, int n, int k, Heap* h1)
{
	assert(h1->_size >= k);
	while (k--)
	{
		printf("%d ", HeapTop(h1));
		HeapPop(h1);
	}
}

//void PrintTopK1(int* a, int n, int k, Heap* h1);
//void PrintTopK1(int* a, int n, int k, Heap* h1)
//{
//	assert(h1->_size >= k);
//	while (k--)
//	{
//		printf("%d ",HeapTop(h1));
//		HeapPop(h1);
//	}
//}
void Swap(int* S1, int* S2);
void Swap(int* S1, int* S2)
{
	int tmp = 0;
	tmp = *S1;
	*S1 = *S2;
	*S2 = tmp;
}
void HeapAscrSort(int* Sort, int n,int parents);
void HeapAscrSort(int* Sort, int n,int parents)
{
	int i = n;
	for (int i = (n-2)/2;i>=0;i--)
	{
		AdjustDown(Sort, n, i);
	}
	int End =n-1;
	while (End>0)
	{
		Swap(&Sort[0], &Sort[End]);
		AdjustDown(Sort, End, parents);
		End--;
	}
}

 big_small_Heap.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include 
#include "big small Heap.h"
int main()
{
	//Heap H1;
	///*HeapCreate(arr,7,6);*/
	HPDataType arr[12] = {0,0,70,50,35,90,100,111,1,121,1211,-200000};
	HeapAscrSort(arr, 12, 0);
	for (int i =0;i<12;i++)
	{
		printf("%d ", arr[i]);
	}
	//HeapCreate(&H1, arr, 9);
	//Print(&H1); 
	//HeapPop(&H1);
	//Print(&H1);
	//HeapPop(&H1);
	//Print(&H1);
	//HeapPop(&H1);
	//Print(&H1);
	//HeapPop(&H1);
	Print(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//HeapPop(&H1);
	//int b = HeapEmpty(&H1);
	//PrintTopK(arr,9,9,&H1);


}

你可能感兴趣的:(算法,数据结构,c++)