2019年5月15日
总结
说实话,数据结构开始以来,我就基本没听懂过。。。
不对,一开始听明白了一点。。
然后就搞不定了
所以这几天写博客一直都是直接上ppt的内容
算了,今天看看堆吧。
堆
根据ppt上所说,堆结构是一种数组对象,它可以被视为一棵完全二叉树。
那么问题来了,我连树都没怎么捣鼓清楚。。。好了我们接着看
树中每个结点与数组中存放该结点中值的那个元素相对应。
至少从图片上我看的很明白。。。。
性质
设数组A的长度为len,二叉树的结点个数为size,size≤len,则A[i]存储二叉树中编号为i的结点值(1≤i≤size),而A[size]以后的元素并不属于相应的堆,树的根为A[1],并且利用完全二叉树的性质,我们很容易求第i个结点的父结点(parent(i))、左孩子结点(left(i))、右孩子结点(right(i))的下标了,分别为:i/2、2i、2i+1;
我看这些话,唯一能理解的就是,如果通俗理解的话,就是知道下标,可以求父节点下标,左右子节点下标。
我们接着来看
堆具有这样一个性质,对除根以外的每个结点i,A[parent(i)]≥A[i]。这种堆又称为“大根堆”;反之,对除根以外的每个结点i,A[parent(i)]≤A[i]的堆,称为“小根堆”。
嗯,这个的意思我估计是除了根结点外每个节点,如果父大于子那么叫“大根堆”,反之就是小根堆“”。
操作
两个操作,增和删。
增
void put(int d) //heap[1]为堆顶
{
int now, next;
heap[++heap_size] = d;//在堆尾加入一个元素
now = heap_size;//把这个结点置为当前结点。
while(now > 1)
{
next = now >> 1;//==now/2;
if(heap[now] >= heap[next]) //比较当前结点和它父结点的大小
break;如果当前结点大于等于父结点,结束
swap(heap[now], heap[next]);
如果当前结点小于父结点,则交换它们的值,并把父结点置为当
前结点。
now = next;
}
}
使用STL
void put(int d)
{
heap[++heap_size] = d;
//push_heap(heap + 1, heap + heap_size + 1); //大根堆
push_heap(heap + 1, heap + heap_size + 1, greater<int>()); //小根堆
}
删
int get() //heap[1]为堆顶
{
int now=1, next, res= heap[1];
heap[1] = heap[heap_size--];//取出堆的根结点的值,把堆的最后一个结点(len)放到根的位置上,把根覆盖掉。把堆的长度减一
while(now * 2 <= heap_size)
{
next = now * 2;//把根结点置为当前父结点pa。
if (next < heap_size && heap[next + 1] < heap[next]) next++;//如果pa无儿子(pa>len/2),则转结束;否则,把pa的两(或一) 个儿子中值最小的那个置为当前的子结点son。
if (heap[now] <= heap[next]) break;
swap(heap[now], heap[next]);//比较pa与son的值,如果fa的值小于或等于son,则结束;否则,交换这两个结点的值,把pa的两(或一) 个儿子中值最小的那个置为当前的子结点son。
now = next;
}
return res;
}
使用STL
int get()
{
//pop_heap(heap + 1, heap + heap_size + 1); //大根堆
pop_heap(heap + 1, heap + heap_size + 1, greater<int>()); //小根堆
return heap[heap_size--];
}
应用
让我先多看几道题,之后再写
感慨
学了这么久,现在依然感觉自己啥都不会。。。