zoukankan      html  css  js  c++  java
  • 堆排序演示 ( 这个 堆排函数将适合所有的堆排, 只需要改一下比较函数)

    通用的堆排函数思想 :

    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("
    
    ");
    }
    

     

    通用的 堆 调整函数 :

    #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 
    ", __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_testc_testheap_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_testc_testheap_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
    

      

  • 相关阅读:
    岩石圈
    地球及其圈层结构
    如何请教一个技术问题
    中国游戏路在何方?
    5.4删除二叉搜索树的任意元素
    5.3 删除二叉搜索树的最大元素和最小元素
    uni-app开发小程序准备阶段
    5.2二叉搜索树遍历(前序、中序、后序、层次、广度优先遍历)
    5.1二叉搜索树基础
    【loj
  • 原文地址:https://www.cnblogs.com/Pitter99/p/14979510.html
Copyright © 2011-2022 走看看