数据结构
Published

August 14, 2018

堆其实是也是一种二叉树,不过他的排序方式更加舒服,对于需要升序或者降序排列的数据非常有用。

代码

binheap.cpp

#include "binheap.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
/**
 * @brief 优先队列-堆的数组实现
 **/
PriorityQueue Initialize(int MaxElements) {
    PriorityQueue H = nullptr;
    if (MaxElements < 0) {
        return nullptr;
    }
    /* 为队列结构体申请内存 */
    H = (PriorityQueue)malloc(sizeof(struct HeapStruct));

    /* 为队列数组申请内存 */
    H->Elements =
        (ElementType *)malloc((MaxElements + 1) * sizeof(ElementType));

    H->Capacity = MaxElements;
    H->Size = 0;
    H->Elements[0] = 0; /* scout element */
    return H;
}
void Destroy(PriorityQueue H) {}
void MakeEmpty(PriorityQueue H) {}
/**
 * @brief 插入的元素都会塞满数组
 **/
void Insert(ElementType X, PriorityQueue H) {
    int i;
    if (IsFull(H)) {
        return;
    }
    /*--->1.指向数组的下一个元素
    |   | 2.判断当前元素是否小于其母节点
    |   | 3.小于:将母节点元素移动到此处 大于:X赋值到此处
    ----v 4.指向母节点的位置 */
    for (i = ++H->Size; H->Elements[i / 2] > X; i /= 2) {
        H->Elements[i] = H->Elements[i / 2];
    }
    H->Elements[i] = X;
}
/**
 * @brief 只需将较小的元素上移即可
 **/
ElementType DeleteMin(PriorityQueue H) {
    int i, Child;
    ElementType MinElement, LastElement;
    if (IsEmpty(H)) {
        return H->Elements[0];
    }
    /* 最小元素 */
    MinElement = H->Elements[1];
    /* 倒数第二个元素 */
    LastElement = H->Elements[H->Size--];

    for (i = 1; i * 2 < H->Size; i = Child) {
        /* 子节点位置为当前节点的2倍 */
        Child = i * 2;
        /* 选择左右子节点中小的那个 */
        if (Child != H->Size && (H->Elements[Child] > H->Elements[Child + 1])) {
            Child++;
        }
        /* 没有到倒数第二个元素的右边 */
        if (LastElement > H->Elements[Child]) {
            /* 上浮 */
            H->Elements[i] = H->Elements[Child];
        } else {
            break;
        }
    }
    /* 交换最后一个元素 */
    H->Elements[i] = LastElement;
    /* 返回删去的元素 */
    return MinElement;
}
ElementType FindMin(PriorityQueue H) {
    if (IsEmpty(H)) {
        return 0;
    } else {
        return H->Elements[1];
    }
}
int IsEmpty(PriorityQueue H) {

    if (H->Size == 0) {
        return true;
    } else {
        return false;
    }
}
int IsFull(PriorityQueue H) {
    if (H->Size == H->Capacity) {
        return true;
    } else {
        return false;
    }
}

void Traversal(PriorityQueue H) {

    if (IsEmpty(H)) {
        printf("Empty\n");
    } else {
        for (int i = 1; i <= H->Size; i++) {
            printf("%d ", H->Elements[i]);
        }
        printf("\n");
    }
}

binheap.h

#ifndef _BinHeap_H
#define _BinHeap_H

#define ElementType int

struct HeapStruct;
typedef struct HeapStruct *PriorityQueue;

PriorityQueue Initialize(int MaxElements);
void Destroy(PriorityQueue H);
void MakeEmpty(PriorityQueue H);
void Insert(ElementType X, PriorityQueue H);
ElementType DeleteMin(PriorityQueue H);
ElementType FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
int IsFull(PriorityQueue H);
void Traversal(PriorityQueue H);
struct HeapStruct {
    int Capacity;
    int Size;
    ElementType *Elements;
};

#endif

main.cpp

#include "binheap.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>

void printUseage(void) {
    printf("\
    二叉堆操作:\n\
    (1):初始化\n\
    (2):插入元素\n\
    (3):删除最小值\n\
    (4):遍历元素\n\
    (q):退出\n\
    ");
}

int main(int argc, char const *argv[]) {
    printUseage();
    PriorityQueue heap;
    ElementType tempint;
    while (true) {
        switch (getchar()) {
        case '1':
            printf("初始化大小为10的堆");
            heap = Initialize(10);
            printf("\n");
            break;
        case '2':
            printf("请输入插入元素:");
            scanf("%d", &tempint);
            Insert(tempint, heap);
            printf("\n");
            break;
        case '3':
            printf("删除:%d", DeleteMin(heap));
            printf("\n");
            break;
        case '4':
            printf("遍历堆:");
            Traversal(heap);
            printf("\n");
            break;
        case 'q':
            exit(EXIT_SUCCESS);
            break;
        default:
            break;
        }
    }

    return 0;
}

Makefile

CC = g++
CFLAGS = #-g 
CLIBS = #-lpthread
 
INCLUDE = $(wildcard ./*.h) # INCLUDE = a.h b.h ... can't be defined like "INCLUDE = ./*.h"
SOURCES = $(wildcard ./*.cpp)
 
TARGET = BinHeap
OBJECTS = $(patsubst %.cpp,%.o,$(SOURCES))
 
$(TARGET) : $(OBJECTS)
    $(CC) $(CFLAGS) $^ -o $@ $(CLIBS)
    rm -rf *.o

$(OBJECTS) : %.o : %.cpp
    $(CC) -c $(CFLAGS) $< -o $@
 
.PHONY : clean
clean:
    rm -rf *.o $(TARGET)  

test

1
2
10
2
8
2
7
2
5
2
3
2
11
2
13
4
3
4
3
4
3
4
q

编译运行

  heap make && cat test | ./BinHeap
g++ -c  binheap.cpp -o binheap.o
g++ -c  main.cpp -o main.o
g++  binheap.o main.o -o BinHeap
rm -rf *.o
    二叉堆操作:
    (1):初始化
    (2):插入元素
    (3):删除最小值
    (4):遍历元素
    (q):退出
    初始化大小为10的堆
请输入插入元素:
请输入插入元素:
请输入插入元素:
请输入插入元素:
请输入插入元素:
请输入插入元素:
请输入插入元素:
遍历堆:3 5 8 10 7 11 13

删除:3
遍历堆:5 7 8 10 13 11

删除:5
遍历堆:7 10 8 11 13

删除:7
遍历堆:8 10 13 11