《github一天,一个算术题》:堆算法接口(堆排序、堆插入和堆垛机最大的价值,并删除)

阅览、认为、编写代码!

/*********************************************
 * [email protected]
 * blog: http://blog.csdn.net/hustyangju
 * 题目:堆排序实现,另外实现接口:取堆最大值并删除、堆插入
 * 思路:堆是在顺序数组原址上实现的。利用全然二叉树的性质。更具最大堆和最小堆的定义实现的。
 * 经典应用场景:内存中堆数据管理
 * 空间复杂度:堆排序是在原址上实现的,为0
 * 时间复杂度:堆排序为O(n lgn) ,取最值O(1)。插入最坏为O(lgn)
*********************************************/
#include <iostream>
#include <algorithm>

using namespace::std;

//对堆排序实现类的定义
class HeapSort
{
 public:
     HeapSort(int *pArray , int nArraySize);//constructor
     ~HeapSort();//destructor
 private:
    int *m_pA;//points to an array
    int m_nHeapSize;//stands for the size
 public:
    void BuildMaxHeap(); //build a heap
    void Sort();//建一个最大堆并排序。依照顺序(由小到大)放在原数组
    int  PopMaxHeap();//取最大堆的最大值
    void InsertMaxHeap(int a);//插入一个新值到最大堆,事实上就是在元素尾部增加一个值,再维护最大堆的性质
    void print();//顺序输出数组
 protected:
    int LeftChild(int node);//取左孩子下标
    int RightChild(int node);//取右孩子下标
    int Parent(int node);//取父节点下标
    void MaxHeapify(int nIndex);//justify the heap
 };

//构造函数初始化
HeapSort::HeapSort( int *pArray, int nArraySize )
{
     m_pA = pArray;
     m_nHeapSize = nArraySize;
}

//析构函数
HeapSort::~HeapSort()
{
}

//取左孩子下标。注意沿袭数组从0開始的习惯
int HeapSort::LeftChild(int node)
{
   return 2*node + 1;// the array starts from 0
}

//取右孩子下标
int HeapSort::RightChild(int node)
{
     return 2*node + 2;
}

//取父节点下标
int HeapSort::Parent(int node)
{
   return (node-1)/2 ;
}

//利用递归维护最大堆的性质。前提是已经建好最大堆。仅仅对变动的结点调用该函数
void HeapSort::MaxHeapify(int nIndex)
{
     int nLeft = LeftChild(nIndex);
     int nRight = RightChild(nIndex);

     int nLargest = nIndex;

     if( (nLeft < m_nHeapSize) && (m_pA[nLeft] > m_pA[nIndex]) )
         nLargest = nLeft;

     if( (nRight < m_nHeapSize) && (m_pA[nRight] > m_pA[nLargest]) )
        nLargest = nRight;

     if ( nLargest != nIndex )//假设有结点变动才继续递归
    {
         swap<int>(m_pA[nIndex], m_pA[nLargest]);
         MaxHeapify(nLargest);
     }
 }

//建造最大堆,思路:对于一个全然二叉树,子数组A[int((n-1)/2)+1]~A[n-1]为叶子结点
//A[0]~A[int((n-1)/2)]为非叶子结点。从下到上,从最后一个非叶子结点開始维护最大堆的性质
 void HeapSort::BuildMaxHeap()
 {
     if( m_pA == NULL )
         return;

     for( int i = (m_nHeapSize - 1)/2; i >= 0; i-- )
    {
         MaxHeapify(i);
     }
}

 //不断取最大堆的最大值A[0]与最后一个元素交换,将最大值放在数组后面。顺序排列数组
 void HeapSort::Sort()
{
     if( m_pA == NULL )
         return;
     if( m_nHeapSize == 0 )
        return;
    for( int i = m_nHeapSize - 1; i > 0; i-- )
     {
        swap<int>(m_pA[i], m_pA[0]);
         m_nHeapSize -= 1;//这个表达式具有破坏性!!

!
         MaxHeapify(0);
    }
}

 //取出最大值,并在堆中删除
 int HeapSort::PopMaxHeap()
 {
    /*if( m_pA == NULL )
          return ;
      if( m_nHeapSize == 0 )
         return ;*/
    int a= m_pA[0];
    m_pA[0]=m_pA[m_nHeapSize-1];
    m_nHeapSize -= 1;
       MaxHeapify(0);
    return a;
 }

 //插入一个值。思路:放在数组最后面(符合数组插入常识),再逐层回溯维护最大堆的性质
 void HeapSort::InsertMaxHeap(int a)
 {
 /*
    if( m_pA == NULL )
          return;
      if( m_nHeapSize == 0 )
         return;
         */
    m_nHeapSize += 1;
    m_pA[m_nHeapSize-1]=a;
    int index=m_nHeapSize-1;
    while(index>0)
    {
        if(m_pA[index]>m_pA[Parent(index)])
        {
            swap(m_pA[index], m_pA[Parent(index)]);
            index=Parent(index);
        }
        else
            index=0;//注意这里。某一层已经满足最大堆的性质了,就不须要再回溯了
    }
 }

 //顺序输出数组
 void HeapSort::print()
 {
     for(int i=0;i<m_nHeapSize;i++)
         cout<<m_pA[i]<<" ";
     cout<<endl;
 }
 int main()
 {
    int a[10]={6,5,9,8,1,0,3,2,7,4};
    //int max;
    cout<<"input an array::"<<endl;
    for(int i=0;i<10;i++)
        cout<<a[i]<<" ";
    cout<<endl;
    HeapSort myHeap(a,10);
    myHeap.BuildMaxHeap();
    cout<<"pop the max number:"<<endl;
    cout<<"the max="<<myHeap.PopMaxHeap()<<endl;
    cout<<"after pop:"<<endl;
    myHeap.print();
    myHeap.InsertMaxHeap(11);
    cout<<"insert a number and sort:"<<endl;
    myHeap.Sort();
   // myHeap.print();
    for(int i=0;i<10;i++)
        cout<<a[i]<<" ";
    cout<<endl;
 }

測试结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHVzdHlhbmdqdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

版权声明:本文博主原创文章。博客,未经同意,不得转载。

时间: 2024-12-23 08:31:16

《github一天,一个算术题》:堆算法接口(堆排序、堆插入和堆垛机最大的价值,并删除)的相关文章

《github一天一道算法题》:堆算法接口实现(堆排序、堆插入和堆取最值并删除)

看书.思考.写代码! /********************************************* * [email protected] * blog: http://blog.csdn.net/hustyangju * 题目:堆排序实现,另外实现接口:取堆最大值并删除.堆插入 * 思路:堆是在顺序数组原址上实现的,利用完全二叉树的性质,更具最大堆和最小堆的定义实现的. * 经典应用场景:内存中堆数据管理 * 空间复杂度:堆排序是在原址上实现的,为0 * 时间复杂度:堆排序为O

【万字总结】图解堆算法、链表、栈与队列(多图预警)

转自:http://blog.csdn.net/nomasp/article/details/50349172 堆算法 什么是堆 堆(heap),是一类特殊的数据结构的统称.它通常被看作一棵树的数组对象.在队列中,调度程序反复提取队列中的第一个作业并运行,因为实际情况中某些时间较短的任务却可能需要等待很长时间才能开始执行,或者某些不短小.但很重要的作业,同样应当拥有优先权.而堆就是为了解决此类问题而设计的数据结构. 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者近似完全二叉树,二叉堆满足堆特性:父

1097:零起点学算法04——再模仿一个算术题

1097: 零起点学算法04--再模仿一个算术题 Time Limit: 1 Sec  Memory Limit: 128 MB   64bit IO Format: %lldSubmitted: 2627  Accepted: 2202[Submit][Status][Web Board] Description 上题会模仿了吧.再来模仿一个. 现在要求你模仿一个乘法的算术题 Input 没有输入 Output 输出9乘以10的值 Sample Output 90 Source 零起点学算法

算法—二叉堆

实现栈或是队列与实现优先队列的最大不同在于对性能的要求.对于栈和队列,我们的实现能够在常数时间内完成所有操作:而对于优先队列,插入元素和删除最大元素这两个操作之一在最坏情况下需要线性时间来完成.我们接下来要讨论的基于数据结构堆的实现能够保证这两种操作都能更快地执行. 1.堆的定义 数据结构二叉堆能够很好地实现优先队列的基本操作.在二叉堆的数组中,每个元素都要保证大于等于另两个特定位置的元素.相应地,这些位置的元素又至少要大于等于数组中的另两个元素,以此类推.如果我们将所有元素画成一棵二叉树,将每

【算法】4 五张图带你体会堆算法

什么是堆 堆(heap),是一类特殊的数据结构的统称.它通常被看作一棵树的数组对象.在队列中,调度程序反复提取队列中的第一个作业并运行,因为实际情况中某些时间较短的任务却可能需要等待很长时间才能开始执行,或者某些不短小.但很重要的作业,同样应当拥有优先权.而堆就是为了解决此类问题而设计的数据结构. 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者近似完全二叉树,二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 当父节点的键值总是大于

白话经典算法系列之七 堆与堆排序

堆排序与高速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先解说下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是全然二叉树或者是近似全然二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)不论什么一个子节点的键值. 2.每一个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于不论什么一个子节点的键值时为最大堆.当父结点的键值总是小于或等于不论什么一个子节点的键值时为最小堆.下图展示一个最小堆

STL中heap算法(堆算法)

 ①push_heap算法 以下是push_heap算法的实现细节.该函数接收两个迭代器,用来表现一个heap底部容器(vector)的头尾,而且新元素已经插入究竟部的最尾端. template <class RandomAccessIterator> inline void push_heap(RandomAccessIterator first,RandomAccessIterator last) { //注意,此函数被调用时,新元素应已置于底部容器的最尾端 _push_heap_au

【坐在马桶上看算法】算法12:堆——神奇的优先队列(下)

接着上一Pa说.就是如何建立这个堆呢.可以从空的堆开始,然后依次往堆中插入每一个元素,直到所有数都被插入(转移到堆中为止).因为插入第i个元素的所用的时间是O(log i),所以插入所有元素的整体时间复杂度是O(NlogN),代码如下. n=0; for(i=1;i<=m;i++) {     n++;     h[ n]=a[ i];  //或者写成scanf("%d",&h[ n]);     siftup(); } 其实我们还有更快得方法来建立堆.它是这样的. 直接

【坐在马桶上看算法】算法11:堆——神奇的优先队列(上)

堆是什么?是一种特殊的完全二叉树,就像下面这棵树一样. 有没有发现这棵二叉树有一个特点,就是所有父结点都比子结点要小(注意:圆圈里面的数是值,圆圈上面的数是这个结点的编号,此规定仅适用于本节).符合这样特点的完全二叉树我们称为最小堆.反之,如果所有父结点都比子结点要大,这样的完全二叉树称为最大堆.那这一特性究竟有什么用呢? 假如有14个数分别是99.5.36.7.22.17.46.12.2.19.25.28.1和92.请找出这14个数中最小的数,请问怎么办呢?最简单的方法就是将这14个数从头到尾