堆排序演示 ( 这个 堆排函数将适合所有的堆排, 只需要改一下比较函数)

通用的堆排函数思想 :

1.对任意一个点进行调整, 需要往两个方向, 父节点和左右子节点进行比较, 交换

2.传入不同的比较函数使得函数变成通用的

 

对一堆数据,需要用堆排: 

(1). 插入方法建堆 (实际工作中这种是更常见)

(2). 基于当前数组进行建堆

 

比较函数 , 交换函数, 打印函数 :\

#include "common.h"

/**
* heap_size 此次调整堆的最大元素个数(因为堆排序过程中,后面已经调整好的就不需要调整了)
* pos 表示此次调整堆的节点
* */

typedef struct Heap
{
	int heap[100];
	int tail;
}Heap;

static int Compare(int idA, int idB)
{
	return idA - idB;
}

//交换堆中任意两个数
static void Swap(Heap *pheap, int posA, int posB)
{
	int ID1 = pheap->heap[posB];
	int ID2 = pheap->heap[posA];
	pheap->heap[posA] = ID2;
	pheap->heap[posB] = ID1;
}

//打印堆中的数据
static void printHeap(Heap *pheap)
{
	for (int i = 1; i < pheap->tail; i++) //从 index = 1 开始保存数据
	{
		printf("%d ", pheap->heap[i]);
	}
	printf("\n\n");
}

 

通用的 堆 调整函数 :

#define parent (pos >> 1) //获得该父节点的左孩子
#define left   (pos << 1)   //获得该父节点的左孩子
#define right  (pos*2 + 1)  //获得该父节点的右孩子, 为啥不能((pos<<2) + 1)

static void adjustHeap(Heap *pheap, int pos, int Compare(int idA, int idB)) // heap_size --> tail
{
	if (pos <= 0)
	{
		return;
	}

	int old_pos = pos;

	while (pos > 1 && Compare(pheap->heap[parent], pheap->heap[pos]) < 0)
	{
		Swap(pheap, pos, parent);
		pos = parent;
	}

	pos = old_pos;

	while ((left < pheap->tail && Compare(pheap->heap[left], pheap->heap[pos]) > 0)
		|| (right < pheap->tail && Compare(pheap->heap[right], pheap->heap[pos]) > 0))
	{
		if ((left < pheap->tail && Compare(pheap->heap[left], pheap->heap[pos]) > 0)
			&& (right < pheap->tail && Compare(pheap->heap[right], pheap->heap[pos]) > 0))
		{
			if (Compare(pheap->heap[left], pheap->heap[right]) > 0) {
				Swap(pheap, pos, left);
				pos = left;
			}
			else
			{
				Swap(pheap, pos, right);
				pos = right;
			}
		}// tail == 12 的时候, pos = 6, 又跟已经交换到 12 的值为 18 的元素交换, 所以不能用 <=
		else if (left < pheap->tail && Compare(pheap->heap[left], pheap->heap[pos]) > 0)
		{
			Swap(pheap, pos, left);
			pos = left;
		}
		else if (right < pheap->tail && Compare(pheap->heap[right], pheap->heap[pos]) > 0)
		{
			Swap(pheap, pos, right);
			pos = right;
		}
	}
}

  

插入式建堆 :

static void maxHeapInsert(Heap *pheap, int key)
{
	int old_pos = pheap->tail;
	pheap->heap[old_pos] = key;
	pheap->tail++;
	adjustHeap(pheap, old_pos, Compare);  //在哪个节点插入就更新那个节点
}

extern void test_heap_qfh()
{
	//simple test
	int arr[] = { 20,14,10,8,7,9,3,2,4,1,80,50,40,70,11,19,12,18,23,35,22 };  // 这个不考虑 0 号元素, 可能好一点
	int len = sizeof(arr) / sizeof(arr[0]); // no need to consider number 0, so the len is 9 only
	printf("%s %d : arr len = %d \n", __FUNCTION__, __LINE__, len);

	Heap heap;
	heap.heap[0] = 0; // 源数组是有值的
	heap.tail = 1; // 从 0 开始计算, 才满足 父节点 = i , 左子节点 = 2*i, 右子节点 = 2*i + 1

	LOGE("will build max heap");
	//build heap (插入式创建 heap)
	for (int i = 0; i < len; i++)
	{
		maxHeapInsert(&heap, arr[i]);
		printHeap(&heap);
	}

	LOGE("will sort all the heap");
	for (int heap_size = len; heap_size >= 2; heap_size--) // heap_size is size of not sort of heap , from tail-1 to 1
	{
		heap.tail--; //先将 tail - 1, 因为 tail-1 才是保存有数据的
		Swap(&heap, 1, heap.tail);//将堆顶元素(通过调整堆获得的最大值)和最后一个交换(剩余未排好序部分的最后一个)
		adjustHeap(&heap, 1, Compare);//之后每次从堆顶开始调整,最大的值将上升到根节点
		printHeap(&heap);
	}
heap.tail = len + 1; printHeap(&heap); }

  

进队 :

test_heap_qfh 101 : arr len = 21
e:\c++\c_test\c_test\heap_sort_not_use0-qfh.cpp test_heap_qfh 107 : will build max heap
20

20 14

20 14 10

20 14 10 8

20 14 10 8 7

20 14 10 8 7 9

20 14 10 8 7 9 3

20 14 10 8 7 9 3 2

20 14 10 8 7 9 3 2 4

20 14 10 8 7 9 3 2 4 1

80 20 10 8 14 9 3 2 4 1 7

80 20 50 8 14 10 3 2 4 1 7 9

80 20 50 8 14 40 3 2 4 1 7 9 10

80 20 70 8 14 40 50 2 4 1 7 9 10 3

80 20 70 8 14 40 50 2 4 1 7 9 10 3 11

80 20 70 19 14 40 50 8 4 1 7 9 10 3 11 2

80 20 70 19 14 40 50 12 4 1 7 9 10 3 11 2 8

80 20 70 19 14 40 50 12 18 1 7 9 10 3 11 2 8 4

80 23 70 20 14 40 50 12 19 1 7 9 10 3 11 2 8 4 18

80 35 70 20 23 40 50 12 19 14 7 9 10 3 11 2 8 4 18 1

80 35 70 20 23 40 50 12 19 22 7 9 10 3 11 2 8 4 18 1 14  //这是大顶堆 , 实际排序后将跟最后一个未排数据进行交换, 最终得到的数据是 从小到大排列

  

index 1 和 index = tail-1 进行交换 :

e:\c++\c_test\c_test\heap_sort_not_use0-qfh.cpp test_heap_qfh 115 : will sort all the heap
70 35 50 20 23 40 14 12 19 22 7 9 10 3 11 2 8 4 18 1

50 35 40 20 23 10 14 12 19 22 7 9 1 3 11 2 8 4 18

40 35 18 20 23 10 14 12 19 22 7 9 1 3 11 2 8 4

35 23 18 20 22 10 14 12 19 4 7 9 1 3 11 2 8

23 22 18 20 8 10 14 12 19 4 7 9 1 3 11 2

22 20 18 19 8 10 14 12 2 4 7 9 1 3 11

20 19 18 12 8 10 14 11 2 4 7 9 1 3

19 12 18 11 8 10 14 3 2 4 7 9 1

18 12 14 11 8 10 1 3 2 4 7 9

14 12 10 11 8 9 1 3 2 4 7

12 11 10 7 8 9 1 3 2 4

11 8 10 7 4 9 1 3 2

10 8 9 7 4 2 1 3

9 8 3 7 4 2 1

8 7 3 1 4 2

7 4 3 1 2

4 2 3 1

3 2 1

2 1

1

  

最终拍好的数据 :

1 2 3 4 7 8 9 10 11 12 14 18 19 20 22 23 35 40 50 70 80

  

posted @ 2021-07-06 23:22  皮特99  阅读(220)  评论(0编辑  收藏  举报