【数据结构】堆的基本操作和堆排序

Heap.h

#pragma once 

#include<stdio.h>

typedef int HeapType;

#define HEAPMAXSIZE 1000

typedef int(*Compare)(HeapType a, HeapType b);

typedef struct Heap{
	HeapType data[HEAPMAXSIZE];
	Compare cmp;
	size_t size;
}Heap;

/*初始化*/
void HeapInit(Heap* heap);

/*插入元素*/
void HeapInsert(Heap* heap, HeapType value);

/*取堆顶元素*/
HeapType HeapRoot(Heap* heap);

/*删除堆顶元素*/
void HeapErase(Heap* heap);

/*堆判空*/
int HeapEmpty(Heap* heap);

/*求堆的大小*/
size_t HeapSize(Heap* heap);

/*销毁堆*/
void HeapDestory(Heap* heap);

/*堆排序*/
void HeapSort(HeapType data[], size_t size);


Heap.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"Heap.h"
#include<stdio.h>
#include<stddef.h>
#include<assert.h>

/*大堆用的函数*/
int no_less(HeapType a, HeapType b) {
	return a > b ? 1 : 0;
}

/*小堆用的函数*/
int less(HeapType a, HeapType b) {
	return a < b ? 1 : 0;
}

/*交换两个数*/
void Swap(HeapType* a, HeapType* b) {
	HeapType tmp = *a;
	*a = *b;
	*b = tmp;
}

/*初始化*/
void HeapInit(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	heap->size = 0;
	heap->cmp = less;
}

/*这里把一个堆中最后一个元素上浮*/
void AdjustUp(HeapType data[], size_t size, Compare cmp, size_t index) {
	assert(data);
	size_t cur = index;
	while (cur) {
		size_t f_cur = (cur - 1) / 2;
		if (cmp(data[cur], data[f_cur])) {
			Swap(&data[cur], &data[f_cur]);
		}
		cur = f_cur;
	}
}

void AdjustDown(HeapType data[], size_t size, Compare cmp, size_t index) {
	assert(data);
	size_t parent = index;
	size_t child = parent * 2 + 1;
	/*直到parent为叶节点的时候就结束循环*/
	while (child < size) {
		//比较子节点,然后得出比较小的结点
		//这里必须判断当前结点的右孩子结点是否存在
		if (child + 1 < size && !cmp(data[child], data[child + 1])) {
			child += 1;
		}
		if (!cmp(data[parent], data[child])) {
			//表示parent大于子节点
			Swap(&data[parent], &data[child]);
		}
		else {
			/*表示当前结点是小于子节点的,就不用再继续往下了*/
			break;
		}
		parent = child;
		child = parent * 2 + 1;
	}
}


/*小堆插入元素*/
void HeapInsert(Heap* heap, HeapType value) {
	if (heap == NULL) {
		return;
	}
	if (heap->size >= HEAPMAXSIZE) {
		/*表示数组已经满了*/
		return;
	}
	/*尾插一个元素,然后上浮*/
	size_t cur = heap->size;
	heap->data[heap->size++] = value;
	/*
	while (1) {
		if (cur <= 0) {
			break;
		}
		//每次与父节点比较
		//如果value小,返回1进入循环
		size_t f_cur = (cur - 1) / 2;
		if (heap->cmp(heap->data[cur], heap->data[f_cur])) {
			Swap(&heap->data[cur], &heap->data[f_cur]);
		}
		cur = f_cur;
	}
	*/
	AdjustUp(heap->data, heap->size, less, heap->size - 1);
}

/*取堆顶元素*/
HeapType HeapRoot(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	if (heap->size == 0) {
		return;
	}
	else {
		return heap->data[0];
	}
}

/*删除堆顶元素*/
void HeapErase(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	if (heap->size == 0) {
		/*表示现在没有元素*/
		return;
	}
	/*先把堆顶元素和最后一个位置的元素交换*/
	Swap(&heap->data[0], &heap->data[heap->size - 1]);
	--heap->size;
	/*然后再把堆重新排好*/
	AdjustDown(heap->data, heap->size, less, 0);
}

/*堆判空*/
int HeapEmpty(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	return heap->size == 0 ? 1 : 0;
}

/*求堆的大小*/
size_t HeapSize(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	return heap->size;
}

/*销毁堆*/
void HeapDestory(Heap* heap) {
	if (heap == NULL) {
		return;
	}
	heap->size = 0;
	heap->cmp = NULL;
}

#if 0
/*
**堆排序
**这里是小堆排序,如果需要大堆排序,需要把AdjustUp和AdjustDown的cmp函数换成no_less
*/
void HeapSort(HeapType data[], size_t size) {
	assert(data);
	if(size == 0 || size == 1) {
		return;
	}
	/*先用数组创建一个*/
	size_t heap_size = 0;
	/*直接用当前数组进行堆的创建*/
	for (; heap_size < size; ++heap_size) {
		AdjustUp(data, heap_size, less, heap_size);
	}
	
	/*然后对这个数组进行排序*/
	while (heap_size > 1) {
		/*每次交换第一个和最后一个*/
		Swap(&data[0], &data[heap_size - 1]);
		--heap_size;
		//然后把前面的元素重新排成堆
		AdjustDown(data, heap_size, less, 0);
	}
}
#elif 1
void HeapSort(HeapType data[], size_t size) {
	if (size == 0 || size == 1) {
		return;
	}
	/*把当前数组变成小堆*/
	//size是数组的元素个数,size - 1是当前最后一个元素的下标位置,然后再 减1除以2,找到最后一个结点的父节点
	size_t start = (size - 1 - 1) / 2;
	/*因为start是无符号长整型,所以在这个循环里不能为0*/
	for (; start > 0; --start) {
		AdjustDown(data, size, less, start);
	}
	AdjustDown(data, size, less, start);

	/*然后对这个数组进行排序*/
	while (size > 1) {
		/*每次交换第一个和最后一个*/
		Swap(&data[0], &data[size - 1]);
		--size;
		//然后把前面的元素重新排成堆
		AdjustDown(data, size, less, 0);
	}
}

#endif


test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
#include<stdio.h>
#include<stdlib.h>

#define TESTHEADR printf("--------------%s--------------\n",__FUNCTION__)

void PrintHeap(Heap* heap, char* msg) {
	if (heap == NULL) {
		return;
	}
	printf("%s:\n\n", msg);
	if (heap->size == 0) {
		printf("堆为空\n");
		return;
	}
	int i = 0;
	for (; i < heap->size; i++) {
		printf("[%d: %d]",i, heap->data[i]);
	}
	printf("\n\n\n");
}

void TestInit() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
}

void TestInsert() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	HeapInsert(&heap, 8);
	HeapInsert(&heap, 2);
	HeapInsert(&heap, 6);
	HeapInsert(&heap, 7);
	HeapInsert(&heap, 4);
	HeapInsert(&heap, 3);
	HeapInsert(&heap, 5);
	HeapInsert(&heap, 0);
	PrintHeap(&heap, "向堆中插入八个数");

	HeapInsert(&heap, 1);
	PrintHeap(&heap, "再插入一个元素");
}

void TestHeapRoot() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	HeapInsert(&heap, 8);
	HeapInsert(&heap, 2);
	HeapInsert(&heap, 6);
	HeapInsert(&heap, 7);
	HeapInsert(&heap, 4);
	HeapInsert(&heap, 3);
	HeapInsert(&heap, 5);
	HeapInsert(&heap, 0);
	PrintHeap(&heap, "向堆中插入八个数");

	HeapType data = HeapRoot(&heap);
	printf("root is %d\n", data);
}

void TestErase() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	HeapInsert(&heap, 8);
	HeapInsert(&heap, 2);
	HeapInsert(&heap, 6);
	HeapInsert(&heap, 7);
	HeapInsert(&heap, 4);
	HeapInsert(&heap, 3);
	HeapInsert(&heap, 5);
	HeapInsert(&heap, 0);
	PrintHeap(&heap, "向堆中插入八个数");

	HeapErase(&heap);
	PrintHeap(&heap, "删除堆顶元素");
}

void TestEmpty() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	int i = HeapEmpty(&heap);
	printf("expect 1, actual: %d\n", i);
	HeapInsert(&heap, 8);
	int j = HeapEmpty(&heap);
	printf("expect 0, actual: %d\n", j);
}

void TestHeapSize() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	HeapInsert(&heap, 8);
	HeapInsert(&heap, 2);
	HeapInsert(&heap, 6);
	HeapInsert(&heap, 7);
	HeapInsert(&heap, 4);
	HeapInsert(&heap, 3);
	HeapInsert(&heap, 5);
	HeapInsert(&heap, 0);
	PrintHeap(&heap, "向堆中插入八个数");

	size_t size = HeapSize(&heap);
	printf("expect 8, actual:%lu\n", size);
}

void TestHeapDestory() {
	TESTHEADR;
	Heap heap;
	HeapInit(&heap);
	HeapInsert(&heap, 8);
	HeapInsert(&heap, 2);
	HeapInsert(&heap, 6);
	HeapInsert(&heap, 7);
	HeapInsert(&heap, 4);
	HeapInsert(&heap, 3);
	HeapInsert(&heap, 5);
	HeapInsert(&heap, 0);
	PrintHeap(&heap, "向堆中插入八个数");

	HeapDestory(&heap);
	PrintHeap(&heap, "销毁堆");
}

void TestHeapSort() {
	HeapType data[] = { 3, 5, 6, 1, 2, 8, 7, 9};
	size_t size = sizeof(data) / sizeof(data[0]);
	HeapSort(data, size);

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

int main() {
	TestInit();
	TestInsert();
	TestHeapRoot();
	TestErase();
	TestEmpty();
	TestHeapSize();
	TestHeapDestory();
	TestHeapSort();
	system("pause");
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值