Preliminary learning of heap sorting-using arrays to simulate heaps

Heap sort

The heap is divided into a large root heap and a small root heap, which is a complete binary tree.

One, binary tree

1.1 Definition

A binary tree with a depth of k and 2 k -1 nodes is called a full binary tree. The number of nodes in each layer of a full binary tree has reached the maximum, that is, there are 2 i-1 nodes (i≥1) on the i- th layer of a full binary tree .

If the nodes of a full binary tree are numbered (starting from 1), the agreed numbering starts from the root node, from top to bottom, and from left to right, then a binary tree with a depth of k and n nodes, if and only When each node has a one-to-one correspondence with the nodes numbered from 1 to n in the full binary tree of depth k, it is called a complete binary tree.

From the definition of full binary tree and complete binary tree, it can be seen that a full binary tree is a special form of a complete binary tree, that is, if a binary tree is a full binary tree, it must be a complete binary tree.

Except for the last branch of a complete binary tree, each branch must have two children, and the last one may have one or two children.

1.2 Nature

If the nodes of a complete binary tree with n nodes are numbered in sequence, then for any node i (1≤i≤n): (Note: [] means rounding down, discarding)

  1. If i=1, then node i is the root of the binary tree without parents; if i>1, then its parent (i) is node [i/2].
  2. If 2i>n, then node i has no left child, otherwise its left child lchild (i) is node 2i.
  3. If 2i+1>n, then node i has no right child, otherwise its right child rchild (i) is node 2i+1.

1.3 Features

The characteristics of a complete binary tree: leaf nodes can only appear in the lowest and sub-lower layers, and the lowest leaf nodes are concentrated in the left part of the tree. It should be noted that a full binary tree is definitely a full binary tree, and a full binary tree is not necessarily a full binary tree.

Second, the implementation of heap sort

A one-dimensional array is used to simulate a complete binary tree. The number of the numbered node corresponds to the subscript of the array. Therefore, the array is stored starting from subscript 1.

2.1 Small root pile

The nature of the small root heap : the value of each child node must be greater than the value of its parent node, but there is no limit between the size of the left and right children. Therefore, in the small root heap, the parent node must be smaller than its child nodes. According to the recursive implementation, the root node must be the smallest value in a complete binary tree.

How to write a pile by hand?

First, two functions are needed: down(x)andup(x)

The down function indicates that the node numbered x is adjusted downward; the up function indicates that the node numbered x is adjusted upward.

On the basis of these two functions, the following functions can be achieved:

  1. Insert a number: heap[++sz]=x; up(sz); Insert at the end
  2. Find the minimum value in the set: heap[1]
  3. Delete the minimum value: heap[1]=heap[sz]; sz– –; down(1); tail instead of head
  4. Delete any element with node k: heap[k]=heap[sz]; sz– –; down(k); up(k);
  5. Modify any element with node k: heap[k]=x; down(k); up(k);

Remove minimum

[AcWing 838. Heap Sort]

Input an integer sequence of length n, and output the small number before m from small to large.

#include <iostream>

using namespace std;

const int N=1e5+10;
int heap[N],sz;//用一维数组heap模拟完全二叉树,sz表示用到的最大结点编号,即树上结点个数

void down(int x)
{
    
    
    //结点为x的 左孩子 2x   右孩子 2x+1
    //小根堆:需要调整时满足条件:父结点大于子节点
    int t=x;
    if (x*2<=sz && heap[t]>heap[x*2])   t=x*2;//假设先和左孩子交换
    if (x*2+1<=sz && heap[t]>heap[x*2+1]) t=x*2+1; //判断是否还需要和右孩子交换
    if (x!=t){
    
    
        swap(heap[t],heap[x]);
        down(t);
    }
}

void up(int x)
{
    
    
    //结点为x(左孩子:偶数,右孩子:奇数)的父结点 :  x/2
    //向上调整时,不必管兄弟节点,只用判断父结点
    while (x/2 && heap[x]<heap[x/2]) {
    
    
        swap(heap[x],heap[x/2]);
        x/=2;
    }
}

int main() {
    
    
    int n,m;
    cin>>n>>m;
    
    // 初始化小根堆
    for (int i = 1; i <= n; ++i)  cin>>heap[i]; //从下标1开始存储
    sz=n;
    for (int i = n/2; i >= 1; --i)  down(i);
    //最后一个叶子结点编号为n,其父结点为n/2,所以最后一个非叶子结点编号为n/2,从这儿开始向下调整,时间复杂度O(n)

    //输出前m小的数,每输出一个数,调整一次小根堆
    for (int i = 0; i < m; ++i) {
    
     //循环m次即可
        cout<<heap[1]<<" ";
        //删除最小的数
        heap[1]=heap[sz];
        sz--;
        down(1);
    }

    return 0;
}

Delete and modify the node with node k

1. Delete and modify the node with subscript k
void del_k(int k)
{
    
    
    heap[k]=heap[sz--];
    down(k);
    up(k);
}

void rep_k(int k,int x)
{
    
    
    heap[k]=x;
    down(k);
    up(k);
}
2. Delete and modify the kth inserted node

【AcWing 839. Simulated Reactor】

Maintain a collection. Initially, the collection is empty. The following operations are supported:

  1. "I x", insert a number x;
  2. "PM", output the minimum value in the current set;
  3. "DM", delete the minimum value in the current set (data guarantees that the minimum value at this time is unique);
  4. "D k", delete the k-th inserted number;
  5. "C kx", modify the k-th inserted number to change it to x;
#include <iostream>

using namespace std;

const int N=1e5+10;
int heap[N],sz;//sz为0时,代表树为null
int getp[N],getb[N],num; //num记录第几次插入

void swap_heap(int i,int j) //交换的结点的下标i j
{
    
    
    swap(heap[i],heap[j]);
    int ki=getb[i],kj=getb[j];
    swap(getp[ki],getp[kj]);
    swap(getb[i],getb[j]);
}

void down(int x)
{
    
    //向下调整,看左右孩子
    int t=x;
    if (x*2<=sz && heap[t]>heap[x*2]) t=x*2;
    if (x*2+1<=sz && heap[t]>heap[x*2+1]) t=x*2+1;
    if (x!=t) {
    
    
        swap_heap(x,t);
        down(t);
    }
}

void up(int x)
{
    
    //向上调整,只看父结点
    while (x/2 && heap[x]<heap[x/2]){
    
    
        swap_heap(x/2,x);
        x/=2;
    }
}

void insert(int x)
{
    
    
    getp[++num]=++sz;
    getb[sz]=num;
    heap[sz]=x;
    up(sz);
}

void del_i(int i)
{
    
       //删除下标为i结点,等价于和最后一个结点出互换并调整该结点
    swap_heap(i,sz--);   //删除根节点 i=1 也算在内
    down(i);
    up(i);
}

void rep_i(int i,int x)
{
    
      //替换下标为i结点的值为x
    heap[i]=x;
    down(i);
    up(i);
}

int main() 
{
    
    
    int n;
    cin>>n;
    string op;
    int k,x;
    while (n--){
    
    
        cin>>op;
        if (op=="I") {
    
    
            cin>>x;   insert(x);
        } else if (op=="PM") {
    
    
            cout<<heap[1]<<endl;
        } else if (op=="DM") {
    
    
            del_i(1);
        } else if (op=="D") {
    
    
            cin>>k;  k=getp[k];
            del_i(k);
        } else if (op=="C"){
    
    
            cin>>k>>x; k=getp[k];
            rep_i(k,x);
        }
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/113729325