• 堆排序实现


    堆排序与快速排序归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。堆排序是跟二叉堆联系在一起的,它是利用二叉堆的性质设计的一种算法。所以它有父节点值总是大于(或小于其所有子节点)。一般情况下,二叉堆是如下所示的:

                                                                             这是一个正序从小到大的序列。

     首先,肯定是插入问题了,我们首先要构造好一个堆。其实这里的插入用插入排序的方法就可以了。他的实现就是直接插入。。

     1 void minHeapFixUp(int *arrayL, int newElementIndex) {
     2     int fatherIndex = (newElementIndex - 1) / 2;
     3     int temp = arrayL[newElementIndex];
     4 
     5     //当新加入的子节点的值小于父节点的时候,将其变为父节点...
     6     //同时向上遍历找到最终的某个元素出现其父元素值大于这个新加入
     7     //节点的时候停止
     8     while (fatherIndex >= 0 && newElementIndex != 0) {
     9         if (arrayL[fatherIndex] < temp)
    10             break;
    11 
    12         arrayL[newElementIndex] = arrayL[fatherIndex];
    13         newElementIndex = fatherIndex;
    14         fatherIndex = (newElementIndex - 1) / 2;
    15     }
    16     arrayL[newElementIndex] = temp;
    17 }
    18 
    19 void insertElement(int* arrayL, int insertIndex, int value) {
    20     arrayL[insertIndex] = value;
    21     minHeapFixUp(arrayL, insertIndex);
    22 }

    二叉堆的堆化什么叫二叉堆的堆化?也就是讲一个序列变成一个符合二叉堆的样子的序列,也就是从父节点要比所有子节点小(或大)。比如:

                                      

    那应该如何用程序对一个序列进行堆化呢【一般情况下我们用数组储存元素】,首先我们要知道一点,父节点和子节点的下标的关系是:

                                                  fatherNode = (sonNode - 1) / 2;

                                                                                                                                 sonNode1 = 2 * father + 1;

                                                                                                                                 sonNode2 = 2 * fatherNode + 2;

    有了这三条,我们就可以根据节点来对其子节点或父节点进行处理了。

    下面我们来谈谈堆化数组

         堆化数组,就是将一个数组变成符合二叉堆性质的数组。那么要如何进行堆化呢,我们可以先将未堆化的数组看成一个二叉树。首先我们从树叶A开始将其与其父节点B变得有序,然后处理其父节点B与B的父节点...如此下去就可以将整个树变成二叉堆。

    我们来看个例子:对数组 Array[3, 20, 12, 23, 45, 22, 32, 65, 2, 19, 34, 90, 67],用图表示如下:

                                                               

    我们可以看出,有第二,第三个叶节点不满足堆的要求,而其他的在父节点和子节点之间已经满足对的条件。所以我们首先将Array[5]和Array[10]互换。Array[4]和Array[9]同理。

    至此,堆化完毕,我们可以看到,这已经是一个有效的二叉堆了。

    那么,我们改怎样用代码来实现呢?如下:

     1 void minHeapFixDown(int *arrayL, int beginIndex, int totalNode) {
     2     int temp = arrayL[beginIndex];
     3     int sonNode = beginIndex * 2 + 1;
     4 
     5     while (sonNode < totalNode) {
     6         //找到最小那个子节点(如果是两个的话)
     7         if (sonNode + 1 < totalNode && arrayL[sonNode] > arrayL[sonNode + 1])
     8             sonNode++;
     9 
    10         if (arrayL[sonNode] >= temp)
    11             break;
    12 
    13         a[beginIndex] = arrayL[sonNode];
    14         //向上遍历
    15         beginIndex = sonNode;
    16         sonNode = beginIndex * 2 + 1;
    17     }
    18     arrayL[beginIndex] = temp;
    19 }
    20 
    21 void makeMinHeap(int *arrayL, int len) {
    22     //遍历每一个子节点,并与父节点比较,进行处理
    23     for (int i = len / 2 - 1; i >= 0; i--)
    24         minHeapFixDown(arrayL, i, len); 
    25 }

    下面来看看怎么删除元素:在二叉堆中,我们删除元素都是讲Array[0]删除然后将最后一个元素补上。然后再进行一次堆化。那么就是如下:

    1 void deleteNode(int* arrayL, int len) {
    2     swap(arrayL[0], arrayL[len - 1]);
    3     minHeapFixDown(arrayL, 0, len - 1);
    4 }

    我们直接将Array[0]交换到数组最后,原因下面再说明。

    到这里,我们就可以进行排序了。其实堆排的原理就是将第一个节点取出,然后再堆化数组,然后再取出新数组的第一个元素,接到原来取出的那个后面。因为第一个元素总是整个数组中最小的一个,所以取出来的数就是一个有序列了。

    1 void heapSort(int *arrayL, int len) {
    2     makeMinHeap(arrayL, len);
    3 
    4     for (int i = len - 1; i >= 0; i--) {
    5         swap(arrayL[0], arrayL[i])
    6         minHeapFixDown(arrayL, 0, i);
    7     }
    8 }

    我们直接将新取出的元素接在数组后面,就可以用节省空间。。

  • 相关阅读:
    TCP通信 小例子
    Socket的简单使用
    Redis练习
    资料
    Redis封装帮助类
    使用Redis的基本操作
    Redis配置主从
    Redis基本设置
    clientHeight ,offsetHeight,style.height,scrollHeight的区别与联系
    服务器操作之如何绑定网站
  • 原文地址:https://www.cnblogs.com/xiezhw3/p/3440604.html
Copyright © 2020-2023  润新知