堆排序演示 ( 这个 堆排函数将适合所有的堆排, 只需要改一下比较函数)
通用的堆排函数思想 :
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