【算法】堆和堆排序

堆和堆排序-基础

  • 堆和堆排序-基础
    • 什么是堆
      • 完全二叉树
      • 堆的性质
    • 堆的好处
    • 堆的操作
      • 定义名词解释
      • 插入新元素
      • 删除堆顶元素
      • 堆排序
    • 对应代码
      • 堆的定义
      • 插入新的元素
      • 删除堆顶
      • 堆排序
      • 其他操作

什么是堆

     堆是一种利用完全二叉树来维护的数据结构,可以方便的取出最大/最小值

完全二叉树

     完全二叉树的定义
     对于堆,你只需知道对于节点i,其子节点为i*2与i*2+1
【算法】堆和堆排序_第1张图片【算法】堆和堆排序_第2张图片
     如图,双方均为二叉树,但是只有左边的是完全二叉树

堆的性质

     堆是建立在完全二叉树的基础上的,有点类似于胜者树,不同的是树的每一个节点都是一个值,因此可能会出现这种情况:
【算法】堆和堆排序_第3张图片
     可以看出7>4>3,但是因为这并不是胜者树,但是仍然是堆
     堆的定义是,对于一个节点i,它大于(小于)其左右孩子大于小于看你维护的是大根堆还是小根堆

堆的好处

取出最大/小节点方便,O(1)
排序方便,O(logn)左右

堆的操作

     一个基础的堆应该可以:

  1. 插入一个新元素
  2. 删除堆顶元素

定义&名词解释

     heap[]数组为我们维护的堆;heapsize为堆的大小
     因而可得——heap[1]为堆顶元素,heap[heapsize]为堆底
     “沉下去”让某个元素在树的深度下降;“升上去”让某个元素在树的位置上升。对于堆来说相当于heap[i]的i变化(变小或变大)

插入新元素

     插入一个新的元素,可以把它变成一个末尾的节点,然后往上浮,直至其符合堆的性质
     至于怎么插入么…因为其符合完全二叉树的性质,所以直接heap[++heapsize]=value,然后让他升上去直至满足堆的性质为止(因为是升上去,只要判断它和它的父亲节点即可)

删除堆顶元素

     如果直接删除堆顶元素的话,可能会导致破坏完全二叉树的结果,所以我们考虑:如果正好让他落在heap[heapsize]上该多好啊
     因此,我们可以这么做:
1. 交换heap[1]heap[heapsize]
2. 删除heap[heapsize](即原本的heap[1])[注:一般的,我们可以直接--heapsize]
3. 让heap[1]沉下去直至满足堆的性质为止
*在沉下去的过程中要确定heap[i]=min(heap[i],heap[i*2],heap[i*2+1])且不能数组越界

堆排序

     有了之前的基础,这些就十分简单了,每次取堆顶然后删除堆顶即可

对应代码

堆的定义

class heapsort
{
    int heap[10001];//利用一个数组实现二叉树
    int heapsize;//也可以用heap[0]代替
    public:
    void insert(int);
    void deletenode();
    void sort();
    int top();
    int size();
};

插入新的元素

void heapsort::insert(int value)
{
    /*
    因为数组维护二叉树的性质,这么做是可行的
    然后将其浮起让它满足堆的性质
    */
    heap[++heapsize]=value;
    int i=heapsize;
    while(i/2>0)
    {
        if(heap[i]2])
        {
            swap(heap[i],heap[i/2]);
            i=i/2;
        }
        else
        {
            return;
        }
    }
}

删除堆顶

void heapsort::deletenode()
{
    /*
    大体意思是,把heap[1]根节点删除,然后用heap[heapsize]代替之
    此举可以保证操作完的树仍然是二叉树
    然后将新heap[1]沉下去使其满足堆的性质
    */
    swap(heap[1],heap[heapsize]);
    heapsize--;
    int i=1;
    int leftnode;
    int rightnode;
    int bigger,smaller;
    while(true)
    {
        leftnode=i*2;rightnode=i*2+1;
        if(leftnode>heapsize)//没有根节点
        {
            return;
        }
        else if(rightnode>heapsize)//没有右儿子
        {
            if(heap[i]>heap[leftnode])
            {
                swap(heap[i],heap[leftnode]);
                i=leftnode;
            }
            else return;
        }
        else//两个都有
        {
            if(heap[leftnode]else
            {
                bigger=leftnode;
                smaller=rightnode;
            }
            if(heap[i]<=heap[smaller]) return;
            if(heap[i]>heap[smaller])
            {
                swap(heap[i],heap[smaller]);
                i=smaller;
            }
            else
            {
                swap(heap[i],heap[bigger]);
                i=bigger;
            }
        }
    }
}

堆排序

void heapsort::sort()
{
    while(heapsize)
    {
        cout<" ";
        deletenode();
    }
}

其他操作

//堆顶
int heapsort::top()
{
    return heap[1];
}
//堆大小
int heapsort::size()
{
    return heapsize;
}

你可能感兴趣的:(———数据结构———,堆)