手写堆
堆是一种特殊的数据结构,它通常是一个可以被看做一棵树的数组对象。这个数组以二叉树的形式来维护。注意:这个二叉树必须是完全二叉树。
堆又分为小根堆和大根堆。顾名思义,小根堆就是每个父亲节点都小于等于其儿子节点;大根堆反之。
而数据用堆存储时并不是随着数组下标增大数据有序增大或减小,而是以下边的方式存储:
根节点下标=孩子下标/2 左孩子下表=根节点下标*2+1 右孩子下标=左孩子下标+1
虽说c++STL提供了优先队列这种东西,但手写堆也有其自己的好处,例如灵活性高,运行快等。
那么如何写堆呢?
首先堆应该在其性质不变的前提下,支持返回堆顶,删除堆顶,插入元素
返回堆顶:
int heap_top() { return heap[1]; }
删除堆顶:
void heap_pop() { heap[1]=heap[tot]; tot--; now_x=1; while(1) { if((now_x<<1)>tot) break; if((now_x<<1)==tot) next_x=tot; else { if(heap[now_x<<1]<heap[(now_x<<1)+1]) next_x=(now_x<<1); else next_x=(now_x<<1)+1; } if(heap[now_x]>heap[next_x]) { swap(heap[now_x],heap[next_x]); now_x=next_x; } else break; } }
插入元素:
void heap_add(int x) { tot++; heap[tot]=x; now_x=tot; while(1) { if(heap[now_x]<heap[now_x>>1]) { swap(heap[now_x],heap[now_x>>1]); now_x>>=1; } else break; } }
维护原理:将父亲节点与子节点比较,若符合规则,则不变;否则交换它们两个的值。