Data structure-heap and binary tree

Table of contents

Preface

Binary tree

1.Traverse the binary tree

2. Number of nodes of binary tree

3. Find the number of leaf nodes

4. Find the height of the binary tree

5. Find the number of nodes in the Kth level of the binary tree

heap

Introduction:

application:

1. Heap sort--O(N*logN)

2.TOP-K

3.Priority queue

Code:

1.Heap.h

2.Heap.c

Illustrations to help explain:

3.Test.c

Summarize



Preface

        This blog covers very few conceptual knowledge points and is not recommended for beginners to learn. The blogger will try his best to use illustrations and codes to facilitate readers' understanding. Please forgive me for the blogger's low level. Readers are welcome to make suggestions, criticisms and corrections.


Binary tree

1.Traverse the binary tree

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

BTNode* BuyNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	node->data = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}

BTNode* CreatTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	return node1;
}

void PreOrder(BTNode* root) {
	if (root == NULL) {
		printf("NULL ");
		return;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

void InOrder(BTNode* root) {
	if (root == NULL) {
		printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

2. Number of nodes of binary tree

//全局变量
//int size = 0;
//void TreeSize1(BTNode* root)
//{
//	if (root == NULL)
//		return;
//
//	++size;
//	TreeSize1(root->left);
//	TreeSize1(root->right);
//}

//传地址
//void TreeSize2(BTNode* root, int* psize)
//{
//	if (root == NULL)
//		return;
//
//	++(*psize);
//	TreeSize2(root->left, psize);
//	TreeSize2(root->right, psize);
//}

//优化
int TreeSize3(BTNode* root)
{
	return root == NULL ? 0 :
		TreeSize3(root->left)
		+ TreeSize3(root->right)
		+ 1;
}

3. Find the number of leaf nodes

int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;

	if (root->left == NULL && root->right == NULL)
		return 1;

	return BTreeLeafSize(root->left) + BTreeLeafSize(root->right);
}

4. Find the height of the binary tree

int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = TreeHeight(root->left);
	int rightHeight = TreeHeight(root->right);

	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

5. Find the number of nodes in the Kth level of the binary tree

int TreeKLevel(BTNode* root, int k)
{
	assert(k > 0);

	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return TreeKLevel(root->left, k - 1)
		+ TreeKLevel(root->right, k - 1);
}

        


heap

Introduction:

1. Complete binary tree

2. Large pile: any parent node of the tree is greater than or equal to the child node;

   Small heap: Any parent node of the tree is less than or equal to the child node.

application:

1. Heap sort--O(N*logN)

//O(N*logN)
void HeapSort(int* a, int n)
{
	// 升序 -- 建大堆
	// 降序 -- 建小堆


	// 建堆--向上调整建堆
	/*for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}*/

	// 建堆--向下调整建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

	// N*logN
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);

		// 调整,选出次小的数
		AdjustDown(a, end, 0);

		--end;
	}
}

2.TOP-K

Find the top K largest (or smallest) elements in the data (for example: the world's top 500 companies, the top 200 college entrance examination rankings, the top 10 popular majors)

a. Heap sort (see sample code above)

Disadvantages:

(1) You need to create a heap first

(2) Space complexity + copy data

b. Use the idea of ​​​​heap sorting to directly adjust the array

//时间复杂度 -- logN

void HeapSort(int* a, int n)
{
	// 向上调整
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}
	// 向下调整 -- O(N)
	/*for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}*/
    //O(N*logN)--相对于一趟堆排序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);

		end--;
	}
}

void TestSort()
{
	int a[] = { 3,1,4,1,0,2,5 };
	HeapSort(a, sizeof(a) / sizeof(int));

	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

c.Limitations

For N integers, find the top K largest ones. The normal idea is to build these N integers into a big pile and pop them K times.

However, in some scenarios, the above ideas cannot solve the problem (for example, when N is very large - 1 billion integers)

Solutions

(1) Take the first K numbers to build a small heap

(2) The remaining data is compared with the top element of the heap in turn. If it is greater than the top element of the heap, replace it into the heap.

(3) The last data in this small heap is the top K largest ones among the N integers.

3.Priority queue

Code:

Array implements heap + dynamic memory management

1.Heap.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

//向上调整
void AdjustUp(HPDataType* a, int child);
//向下调整
void AdjustDown(int* a, int n, int parent);

void HeapInit(HP* php);
void HeapDestroy(HP* php);

//插入一个结点
void HeapPush(HP* php, HPDataType x);
//删除堆顶的元素
void HeapPop(HP* php);

//取堆顶元素
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
int HeapSize(HP* php);

2.Heap.c

#include "Heap.h"

void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->capacity = 0;
	php->size = 0;
}

void HeapDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->capacity = 0;
	php->size = 0;
}

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//while(parent >= 0) 行不行?
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//选出左右孩子中较小的那一个
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}

		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);

			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//log_2(N)
void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	//如满拓展空间
	if (php->size == php->capacity)
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		php->a = tmp;
		php->capacity = newCapacity;
	}
	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

void HeapPop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(!HeapEmpty(php));

	return php->a[0];
}

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->size == 0;
}

int HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

Illustrations to help explain:

a.HeapPush (insert an element) - time complexity O(logN)

For a complete binary tree, if the subscript n of a node is known, how to find its parent node and the left and right child nodes?

parent = (n - 1) / 2;

leftchild = n * 2 + 1, rightchild = n * 2 + 2;

b.HeapPop (delete the top element of the heap) - time complexity O(logN)

3.Test.c

#include "Heap.h"

int Test0()
{
	HP hp;
	HeapInit(&hp);
	int a[] = { 65,100,21,32,520,64 };

	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		HeapPush(&hp, a[i]);
	}

	while (!HeapEmpty(&hp))
	{
		int top = HeapTop(&hp);
		printf("%d\n", top);
		HeapPop(&hp);
	}

	return 0;
}

//对数组进行堆排序

// 可以这么玩吗?--可以
// 弊端:
// 1、需要先创建一个堆,太麻烦
// 2、空间复杂度+拷贝数据
// 
//void HeapSort(int* a, int n)
//{
//	HP hp;
//	HeapInit(&hp);
//	// N*logN
//	for (int i = 0; i < n; ++i)
//	{
//		HeapPush(&hp, a[i]);
//	}
//
//	// N*logN
//	int j = 0;
//	while (!HeapEmpty(&hp))
//	{
//		int top = HeapTop(&hp);
//		a[j++] = top;
//		HeapPop(&hp);
//	}
//
//	HeapDestroy(&hp);
//}

//O(N*logN)
void HeapSort(int* a, int n)
{
	// 升序 -- 建大堆
	// 降序 -- 建小堆


	// 建堆--向上调整建堆
	/*for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}*/

	// 建堆--向下调整建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

	// N*logN
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);

		// 再调整,选出次小的数
		AdjustDown(a, end, 0);

		--end;
	}
}

void TestSort()
{
	int a[] = { 3,1,8,4,5,2,0 };
	HeapSort(a, sizeof(a) / sizeof(int));

	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

int main()
{
	//Test0();
	
	TestSort();

	return 0;
}


Summarize

Guess you like

Origin blog.csdn.net/weixin_72501602/article/details/130791043