堆排序 - 通过最大堆实现 - C语言

堆排序实际上是利用了完全二叉树的公式化描述特性,将一个数组以最大堆的方式呈现,并逐一删除其根节点。

几个概念要理解:

假设完全二叉树中一元素的序号为i,1 <= i <= n,则以下关系成立:

1. 当i=1时,该元素为二叉树的根。若i>1,则该元素父节点的编号为i/2(int取整);

2. 当2i>n时,该元素无左孩子,否则,其左孩子的编号为2i;

3. 当2i+1>n时,该元素无右孩子 ,否则,其右孩子的编号为2i+1。

最大树:每个节点的值都大于或等于其子节点值的树。

最大堆:完全二叉树 && 最大树。

MaxHeap.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define RET_TRUE  0
#define RET_FALSE -1

struct MaxHeap {
	int *data;
	int total_size;
	int cur_size;
};

static struct MaxHeap * maxheap_init(int size);
static void maxheap_destroy(struct MaxHeap **heap);
static int maxheap_insert(struct MaxHeap *heap, int ele);
static int maxheap_delete_max(struct MaxHeap *heap, int *ret_ele);

static void swap_int(int *a, int *b)
{
	int c = *a;
	*a = *b;
	*b = c;
}

static struct MaxHeap * maxheap_init(int size)
{
	struct MaxHeap *heap;

	if(size <= 0)
		return NULL;

	heap = malloc(sizeof(struct MaxHeap));	
	if(NULL == heap)
		return NULL;
	memset(heap, 0, sizeof(struct MaxHeap));

	heap->data = malloc(size * sizeof(int));
	if(NULL == heap->data) {
		free(heap);
		return NULL;
	}
	memset(heap->data, 0, size * sizeof(int));

	heap->total_size = size;
	heap->cur_size   = 0;

	return heap;
}

static void maxheap_destroy(struct MaxHeap **heap)
{
	struct MaxHeap *m_heap;
	
	m_heap = *heap;
	if(m_heap) {
		if(m_heap->data) {
			free(m_heap->data);
			m_heap->data = NULL;
		}

		free(m_heap);
		m_heap = NULL;
	}
}

static int maxheap_insert(struct MaxHeap *heap, int ele)
{
	int i;

	if(NULL == heap || NULL == heap->data 
		|| heap->total_size == heap->cur_size) /* heap is full */
		return RET_FALSE;

	heap->data[heap->cur_size++] = ele;
	for(i = heap->cur_size - 1; i > 0; i--) {
		if(heap->data[i] > heap->data[i/2]) {
			swap_int(&heap->data[i], &heap->data[i/2]);
		}
	}

	return RET_TRUE;
}

static int maxheap_delete_max(struct MaxHeap *heap, int *ret_ele)
{
	int i, left_i, right_i;
	if(NULL == heap || NULL == ret_ele 
		|| heap->cur_size <= 0)   /* heap is empty */
		return RET_FALSE;

	*ret_ele = heap->data[0];
	heap->data[0] = heap->data[--heap->cur_size];

	i = 1;
	left_i = 2*i;
	right_i = 2*i+1;

	while(left_i <= heap->cur_size) {
		if(right_i <= heap->cur_size) {  /* Both left child and right child exist.  */
			if(heap->data[left_i-1] > heap->data[i-1]
				&& heap->data[left_i-1] > heap->data[right_i-1])	{
				swap_int(&heap->data[left_i-1], &heap->data[i-1]);   /* Choose left child as the biggest. */
			} else if(heap->data[right_i-1] > heap->data[i-1] 
				&& heap->data[right_i-1] > heap->data[left_i-1]) {
				swap_int(&heap->data[right_i-1], &heap->data[i-1]);  /* Choose right child as the biggest. */
			}	
		} else {  /* Only left child exists. */
			if(heap->data[i-1] < heap->data[left_i-1])
				swap_int(&heap->data[i-1], &heap->data[left_i-1]);
		}

		i++;
		left_i = 2*i;    /* 根据完全二叉树的特性寻找左/右子节点 */
		right_i = 2*i+1; 
	}

	return RET_TRUE;
}

static void print_max_heap(struct MaxHeap *heap)
{
	int i = 0;
	if(heap && heap->data) {
		printf(" Max heap: ");
		for(i = 0; i < heap->cur_size; i++)
			printf("%d ", heap->data[i]);
		printf("\n");
	}
}


int main()
{
	int ele, index;
	struct MaxHeap * max_heap = maxheap_init(10);
	maxheap_insert(max_heap, 45);
	maxheap_insert(max_heap, 32);
	maxheap_insert(max_heap, 78);
	maxheap_insert(max_heap, 65);
	maxheap_insert(max_heap, 12);
	maxheap_insert(max_heap, 5);
	maxheap_insert(max_heap, 90);
	maxheap_insert(max_heap, 22);
	maxheap_insert(max_heap, 89);
	maxheap_insert(max_heap, 2);
	
	print_max_heap(max_heap);

	index = max_heap->cur_size;
	printf("Heap Sort: ");
	while(index--) {
		maxheap_delete_max(max_heap, &ele);
		printf("%d ", ele);
	}
	printf("\n");

	return 0;
}


猜你喜欢

转载自blog.csdn.net/weixin_42263483/article/details/80953104