"Data Structure Cultivation Manual"----The sequential structure and implementation of binary tree

1. The sequential structure of the binary tree

Ordinary binary trees are not suitable for storing in arrays, because there may be a lot of wasted space. A complete binary tree is more suitable for storage in a sequential structure. In reality, we usually store the heap (a kind of binary tree) using an array of sequential structures. It should be noted that the heap here and the heap in the virtual process address space of the operating system are two different things. One is the data structure and the other is the management system in the operating system. A region of memory is segmented.

image-20220403105214178

2. The concept and structure of the heap

If there is a set of keys K = { k 0 , k 1 , k 2 ..., k n-1 }, store all its elements
in a one-dimensional array in the order of a complete binary tree, and satisfy: K i <= K 2*i+1 and K i <= K 2*i+2 ( K i >=
K 2*i+1 and K i <= K 2*i+2 ) i = 0, 1,
2 ..., is called a small heap (or large heap). The heap with the largest root node is called the max heap or the big root heap, and the heap with the smallest root node is called the min heap or the small root heap.

Quick description:

Big heap (big root heap): The father in the tree is greater than (equal to) the child.

Small heap (small root heap): The father in the tree is less than (equal to) the child.

Properties of the heap:

  • The value of a node in the heap is always not greater or less than the value of its parent node;

  • A heap is always a complete binary tree.

    image-20220403122953339

Application scenarios: heap sort, topk.

3. Simulation implementation of linear heap

3.1 The basic structure definition of the heap

typedef int HPDataType;//堆中存放的数据,假设是整型
typedef struct Heap
{
	HPDataType* a;//指针指向堆中存储的数据
	size_t size;//堆中当前元素的数目
	size_t capacity;//堆中所能存储数据的容量
}HP;

3.2 Initialization of the heap

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

3.3 Destruction of the heap

void HeapDestory(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
}

3.4 Insertion of heap data

Ideas:

Time complexity: log(N)

image-20220403155004910

void Swap(HPDataType* pa, HPDataType* pb)//交换函数:交换数组中的两个元素
{
	HPDataType tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
void AdjustUp(HPDataType* a, size_t child )//堆的向上调整
{
	size_t parant = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parant])//此处如果是<就是小堆,如果是>就是大堆
		{
			Swap(&a[child], &a[parant]);
			child = parant;
			parant = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void HeapPush(HP* php, HPDataType x)
{
	assert(php);
    //判断是否需要扩充并进行扩充
	if (php->size == php->capacity)
	{
		size_t newCapacity = php->capacity == 0 ? 2 : 2 * php->capacity;
		HPDataType*tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType)*newCapacity);
		if (tmp == NULL)
		{
			printf("realloc failed\n");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}
	php->a[php->size] = x;
	php->size++;
	//向上调整,控制保持是堆
	AdjustUp(php->a, php->size - 1);
}

3.5 Heap Deletion

Ideas:

  1. Swap the first number with the number in the last position

  2. delete last data

  3. adjust down

    Below is an illustration of the downward adjustment:

    Time Complexity: O(log 2 N)

    image-20220408163509379

void Swap(HPDataType* pa, HPDataType* pb)//交换函数:交换数组中的两个元素
{
	HPDataType tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}

void AdjustDown(HPDataType* a, size_t size,size_t root)
{
	size_t parant = root;
	size_t child = 2*parant+1;
	
	while (child<size)
	{
		if (child+1<size &&a[child + 1] < a[child])//此时后面的这个如果是<就是小堆,如果是>就是大堆
			++child;
		if (a[child] < a[parant])//如果是<就是小堆,如果是>就是大堆
		{
			Swap(&a[child], &a[parant]);
			parant = child;
			child = 2 * parant + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapPop(HP* php)
{
	assert(php);
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	AdjustDown(php->a, php->size, 0);
}

Q: Why doesn't the deletion of the heap directly cover from the back to the front, and cover the first element?

Answer: First, the time complexity is O(N). Second, the original structure of the heap may be disrupted, and at the same time, the original properties of the heap may be lost and become no longer a heap, unless the original array elements of the heap are from small to large or from The properties of the heap can be maintained only when the big to the small is ordered, but even in this case the structure of the heap will still be disrupted, that is, their parent-child relationship will be destroyed.

3.6 Determine whether the linear heap is empty

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

3.7 Finding the Number of Linear Heap Elements

size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

3.8 Return the elements of the linear heap header

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

3.9 Printing the elements of a linear heap

void HeapPrint(HP* php)
{
	assert(php);
	for (size_t i = 0; i < php->size; i++)
	{
		printf("%d ", php->a[i]);
	}
	printf("\n");
}

Guess you like

Origin blog.csdn.net/m0_57304511/article/details/124246461