做3D打印樣品用什么外貿(mào)網(wǎng)站好2345網(wǎng)址大全
今天我們來(lái)學(xué)習(xí)堆,它也是二叉樹(shù)的一種(我滴神樹(shù)!)
目錄
- 堆的介紹:
- 堆的代碼實(shí)現(xiàn):
- 堆的結(jié)構(gòu)體創(chuàng)建:
- 堆的初始化:
- 堆的銷(xiāo)毀:
- 堆的push:
- 堆的pop:
- 判空 && 求Top元素 && 求size:
- 完整源碼:
堆的介紹:
如果有一個(gè)關(guān)鍵碼的集合K = { , , ,…, },把它的所有元素按完全二叉樹(shù)的順序存儲(chǔ)方式存儲(chǔ) 在一個(gè)一維數(shù)組中,并滿足: <= 且
<= ( >= 且 >= ) i = 0,1,
2…,則稱(chēng)為小堆(或大堆)。將根節(jié)點(diǎn)最大的堆叫做最大堆或大根堆,根節(jié)點(diǎn)最小的堆叫做最小堆或小根堆。
堆的性質(zhì):
- 堆中某個(gè)節(jié)點(diǎn)的值總是不大于或不小于其父節(jié)點(diǎn)的值;
- 堆總是一棵完全二叉樹(shù)。
堆的代碼實(shí)現(xiàn):
堆的結(jié)構(gòu)體創(chuàng)建:
typedef int HpDataType;typedef struct Heap
{int size;int capacity;HpDataType* a;
}Hp;
堆的初始化:
這里我們選擇先不給賦值,等push時(shí)再給賦值
void HpInit(Hp* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}
堆的銷(xiāo)毀:
雖然與初始化相似,但是不能混用
void HpDestory(Hp* php)
{assert(php);free(php->a);php->a = NULL;php->size = 0;php->capacity = 0;
}
堆的push:
我們需要一個(gè)向上調(diào)整算法:
這里我們選擇創(chuàng)建小堆
因?yàn)槲覀冎挥衟ush需要?jiǎng)?chuàng)建newnode,故不需要重新封裝一個(gè)CreatNewnode函數(shù)調(diào)整算法時(shí)需要傳的參數(shù)是
void HpPush(Hp* php, HpDataType x)
{assert(php);if (php->capacity == php->size){int newcapacity = (php->capacity == 0 ? 4 : php->capacity * 2);HpDataType* tmp = (HpDataType*)realloc(php->a, sizeof(HpDataType)* newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}
向上調(diào)整算法:
注意:
我們?cè)谶M(jìn)行向上傳參時(shí),要傳入動(dòng)態(tài)數(shù)組的地址和最后一個(gè)葉子節(jié)點(diǎn)的下標(biāo),為什么不是傳入結(jié)構(gòu)體的地址原因會(huì)在后來(lái)講解
Swap(HpDataType* e1, HpDataType* e2)
{HpDataType tmp = *e1;*e1 = *e2;*e2 = tmp;
}void AdjustUp(HpDataType* a, int child)
{int parent = (child - 1) / 2;//假設(shè)進(jìn)入循環(huán)時(shí)child > 0//這里選擇child = 0作為結(jié)束標(biāo)志是因?yàn)楫?dāng)child = 0時(shí)//a[child] 與 a[parent]已經(jīng)交換過(guò)一次了,//他們兩現(xiàn)在同時(shí)指向下標(biāo)位0,不需要在交換了while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);}else{break;}child = (child - 1) / 2;parent = (parent - 1) / 2;}
}
堆的pop:
注意:
我們?cè)谶M(jìn)行pop時(shí),并不是pop
最后的葉子節(jié)點(diǎn),這樣沒(méi)有實(shí)際意義,我們要pop
的是根節(jié)點(diǎn),這樣是有實(shí)際意義的,比如Top k
問(wèn)題,堆排序等
pop主體部分:
void HpPop(Hp* php)
{assert(php);Swap(&php->a[php->size - 1], &php->a[0]);php->size--;AdjustDown(php->a, php->size, 0);
}
同理我們也需要一個(gè)向下調(diào)整算法
注意:
傳參時(shí)仍然是傳動(dòng)態(tài)數(shù)組a的地址,另外還需要size與根節(jié)點(diǎn)0的下標(biāo),
size用于判斷是否超出堆的范圍,0作為parent的初始值
向下調(diào)整時(shí)我們需要找出孩子節(jié)點(diǎn)中較大或較小的那個(gè),在這種情況下我們可以使用假設(shè)法,假設(shè)后在進(jìn)行判斷是否正確,將兩段邏輯變成一段邏輯
AdjustDown(HpDataType* a, int size, int parent)
{//假設(shè)法int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child] > a[child + 1]){child++;}if (a[parent] > a[child]){Swap(&a[parent], &a[child]);}else{break;}child = child * 2 + 1;parent = parent * 2 + 1;}
}
判空 && 求Top元素 && 求size:
bool HpEmpty(Hp* php)
{assert(php);return php->size == 0;
}int HpTop(Hp* php)
{assert(php);//注意為空assert(php->size);return php->a[0];
}int HpSize(Hp* php)
{assert(php);return php->size;
}
完整源碼:
heap.c
#define _CRT_SECURE_NO_WARNINGS 1#include"heap.h"void HpInit(Hp* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}void HpDestory(Hp* php)
{assert(php);free(php->a);php->a = NULL;php->size = 0;
}Swap(HpDataType* e1, HpDataType* e2)
{HpDataType tmp = *e1;*e1 = *e2;*e2 = tmp;
}void AdjustUp(HpDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);}else{break;}child = (child - 1) / 2;parent = (parent - 1) / 2;}
}
//小堆
void HpPush(Hp* php, HpDataType x)
{assert(php);if (php->capacity == php->size){int newcapacity = (php->capacity == 0 ? 4 : php->capacity * 2);HpDataType* tmp = (HpDataType*)realloc(php->a, sizeof(HpDataType)* newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}AdjustDown(HpDataType* a, int size, int parent)
{//假設(shè)法int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child] > a[child + 1]){child++;}if (a[parent] > a[child]){Swap(&a[parent], &a[child]);}else{break;}child = child * 2 + 1;parent = parent * 2 + 1;}
}void HpPop(Hp* php)
{assert(php);Swap(&php->a[php->size - 1], &php->a[0]);php->size--;AdjustDown(php->a, php->size, 0);
}bool HpEmpty(Hp* php)
{assert(php);return php->size == 0;
}int HpTop(Hp* php)
{assert(php);assert(php->size);return php->a[0];
}int HpSize(Hp* php)
{assert(php);return php->size;
}
heap.h
#pragma once#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int HpDataType;typedef struct Heap
{int size;int capacity;HpDataType* a;
}Hp;void HpInit(Hp* php);void HpDestory(Hp* php);void HpPush(Hp* php, HpDataType x);void HpPop(Hp* php);bool HpEmpty(Hp* php);int HpSize(Hp* php);int HpTop(Hp* php);
有疑問(wèn)可以及時(shí)找博主交流