【数据结构】堆 的增,删,查,改的实现

选用 向上调整法 与 向下调整法的时机:

     AdjustDown() 与 AdjustUp() 的选取:
    注意 AdjustDown() 与 AdjustUp() 的参数不同


    在不进行插入元素或者删除元素的前提下:
    如果要建立小根堆,则需要使用 AdjustUp(),
    如果要建立大根堆,则需要使用 AdjustDown().
    
    当要在堆中插入元素时:
    无论是建立小根堆还是大根堆,则需要使用 AdjustUp(),
    
    当要在堆中删除元素时:
    无论是建立小根堆还是大根堆,则需要使用 AdjustDown()

堆操作的代码实现:

#include <iostream>

using namespace std;

int main()
{
	/*实现堆的内存结构是数组;
	堆分为大根堆和小根堆;
	堆是一个完全二叉树。*/
	typedef int HeapDataType;
	typedef struct Heap
	{
		HeapDataType *arr;
		int size;
		int capacity;
	}Heap;


	//向下调整算法:
	void AdjustDown(int *arr, int n, int parent)//要传递的是三个参数
	{
		int child = parent * 2 + 1;//默认先求出左孩子结点

		while (child < n)
		{
			/*child + 1 < n 的原因是预防在访问数组时发生越界,
			因为默认 child 是左孩子结点,
			而堆又是完全二叉树,
			所以当访问到左孩子结点时,一定不会发生数组越界,
			因为最后右树的右孩子结点可有可无,
			所以要防止访问到右孩子越界。*/
			if ( (child + 1 < n) && arr[child] < arr[child + 1])/*左孩子的结点比右结点小,
				                        而父亲结点是要与俩个孩子结点中最大的那一个结点进行交换*/
			{
				child++;
			}

			if (arr[parent] < arr[child])
			{
				swap(&arr[parent], &arr[child]);
				parent = child;
				child = parent * 2 + 1;			
			}
			else
			{
				break;
			}
		}
	}

	//初始化堆(建堆):
	/*注意:
	这里的初始化不像顺序表那样只是简单的赋值,
	根据堆的特性,
	不光要赋值,还得对数组里面的元素进行排序(使用向下调整算法进行大根堆中元素的排序)。
	
	void HeapInit(Heap *ph, int n)/*第一个参数是堆的地址,
													 第二个参数是动态数组,
													 第三个参数是堆中元素的个数*/
	{
		assert(ph);
	
		HeapDataType *tmp = (HeapDatatType *)malloc(sizeof(HeapDataType) * n);
		if (ph->arr == NULL)
		{
			printf("malloc fail\n");

			exit(-1);
		}
		ph->arr = tmp;

		php->size = n;
		php->capacity = n;

		//建堆:
		for (int i = (n - 1 - 1) / 2; i >= 0; i--)
		{
			AdjustDown(php->a, php->size, i);
		}
	}

	/*-----------------------------------------------------------------------------------*/
	
	void HeapInit(Heap *hp)
	{
		assert(hp);
		hp->arr = NULL;
		hp->size = hp->capacity = 0;
	}

	//堆结构的销毁:
	/*注意:
	它没有对堆的整体地址 free 掉*/
	void HeapDestroy(Heap *hp)
	{
		assert(hp);
		free(hp->arr);
		hp->arr = NULL;
		
		hp->size = hp->capzcity = 0;
	}

	//堆的插入:
	void HeapPush(Heap *ph, HeapDataType x)
	{
		if (ph->size == ph->capacity)
		{
			int newcapacity == 0 ? 4 : ph->capacity * 2;/*对于 hp->capacity 的更新,
														必须创建一个新的变量,
														因为有可能 capacity 的初始值为 0,
														如果直接与 sizeof(HeapDataType) 相乘,
														则会出错。*/
			HeapDataType *tmp = (HeapDataType *)realloc(ph->arr, sizeof(HeapDataType)*newcapacity);
			if (tmp == NULL)
			{
				cout << "realloc is fail" << endl;
				exit(-1);
			}

			ph->arr = tmp;
			ph->capacity = newcapacity;
		}

		ph->arr[size] = x;
		ph->size++;

		//插入后就要对整个数组进行重新排序,使之变为大根堆或小根堆,
		/*这里以小根堆为例,使用向上调整算法*/
		AdjustUp(hp->arr,hp->size-1);
	}

	//向上调整算法:
	void AdjustUp(HeapDataType *arr, int child)//无需传入双亲结点的下标,只需将插入元素的下标传入即可
	{
		assert(arr);
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			if (arr[child] < arr[parent])
			{
				swap(&arr[child], &arr[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}

	//堆元素的删除(删除数组的首元素):
	/*如果要删除堆中的元素时,一般从堆的末尾开始删除,
	所以如果想要删除数组中的第一个元素,
	则需要将其与末尾最后一个元素互换,
	然后进行 size--,
	最后对堆重新进行排序使之变为大根堆或小根堆*/
	void HeapPop(Heap *hp)//注意其参数是堆的地址
	{
		assert(hp);
		swap(&hp->arr[0], &hp->arr[hp->size - 1]);
		
		hp->size--;//只需减小size就算是对于元素的删除

		AdjustDown(hp, hp->size, 0);

	}

	//AdjustDown() 与 AdjustUp() 的选取:
	/*注意 AdjustDown() 与 AdjustUp() 的参数不同*/
	/*在不进行插入元素或者删除元素的前提下:
	如果要建立小根堆,则需要使用 AdjustUp(),
	如果要建立大根堆,则需要使用 AdjustDown().
	
	当要在堆中插入元素时:
	无论是建立小根堆还是大根堆,则需要使用 AdjustUp(),
	
	当要在堆中删除元素时:
	无论是建立小根堆还是大根堆,则需要使用 AdjustDown()*/

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值