文章目录
- 🏔️堆是什么?
- 🏔️C++ 标准库
- 🏔️手动实现
- ⛰️原理简介
- ⛰️C++
- ⛰️C语言
- ⭐END
- 🌟交流方式
🏔️堆是什么?
堆简介 - OI Wiki
堆是一棵树,其每个节点都有一个键值,且每个节点的键值都大于等于/小于等于其父亲的键值。
每个节点的键值都大于等于其父亲键值的堆叫做小根堆,否则叫做大根堆。
容器适配器 - OI Wiki
优先队列 std::priority_queue
是一种 堆,一般为 二叉堆。
本文以 1845. 座位预约管理系统 为例进行使用和简单实现的讲解。(本题是小顶堆)
🏔️C++ 标准库
std::priority_queue - cppreference.com
class SeatManager {std::priority_queue<int, vector<int>, greater<int>> heap;public:SeatManager(int n) {for (int i = 1; i <= n; i += 1) {heap.push(i);}}int reserve() {int ret = heap.top();heap.pop();return ret;}void unreserve(int seatNumber) {heap.push(seatNumber);}
};
algorithm 堆操作
class SeatManager {vector<int> heap;public:SeatManager(int n) {for (int i = 1; i <= n; ++i) {heap.push_back(i);}}int reserve() {pop_heap(heap.begin(), heap.end(), greater<int>());int tmp = heap.back();heap.pop_back();return tmp;}void unreserve(int seatNumber) {heap.push_back(seatNumber);push_heap(heap.begin(), heap.end(), greater<int>());}
};
🏔️手动实现
⛰️原理简介
核心:用数组模拟完全二叉树。
用数组模拟完全二叉树,下标[0, n - 1],节点i
的所有子树为left = i * 2 + 1
,right = i * 2 + 2
。
两个重要操作,注意不要越界。
堆调整
针对我们要维护的节点fa
,对其左右子节left, right
点进行比较,找出最值。交换到当前节点fa
上。
然后交换后的位置也要同样的维护,因此可以进行迭代或者递归。
// [0, n - 1]
int fa;
int left = (fa << 1) + 1;
int right = (fa << 1) + 2;
// e.g.
// fa = 0 left = 1 right = 2
尾部新元素维护
因为我们是数组模拟,不是链式的二叉树。因此直接在末尾添加元素比较方便。
而末尾的新元素要和其父元素进行比较。如果要提升,则将父元素复制到子节点。
同理不断直到根部的迭代或则递归。
// [0, n - 1]
int leaf;
int fa = (leaf - 1) / 2;
// e.g.
// leaf = 7 fa = 3
// leaf = 8 fa = 3
⛰️C++
座位预约管理系统 - 提交记录 - 力扣(LeetCode)
namespace lotus {
template <typename T, typename Compare = std::less<T>>
struct Heap {
public: // Member typesusing value_compare = Compare;using value_type = T;using size_type = std::size_t;private: // Memberstd::vector<value_type> heap;value_compare cmp;public: // constructor & distructorHeap() = default;~Heap() = default;public: // Element accessvalue_type& top() {return heap[0];}public: // Capacitybool empty() const {return heap.empty();}size_type size() const {return heap.size();}public: // Modifiersvoid push(const value_type& value) {heap.push_back(value);// 自底向上进行调整int i = this->size() - 1;for (; i > 0 && cmp(value, heap[(i - 1) >> 1]); i = (i - 1) >> 1) {heap[i] = heap[(i - 1) >> 1];}heap[i] = value;}void pop() {value_type ret = heap.front();heap.front() = heap.back();heap.pop_back();if (this->size()) {heapify(heap, 0, this->size() - 1);}}public:static void heapify(vector<int>& arr, int fa, int border) {assert(fa <= border);assert((int)arr.size() - 1 <= border);value_compare cmp{};while ((fa << 1) + 1 <= border) {int left = (fa << 1) + 1;int right = (fa << 1) + 2;int idx = fa;if (left <= border && cmp(arr[left], arr[idx])) {idx = left;}if (right <= border && cmp(arr[right], arr[idx])) {idx = right;}if (idx != fa) {swap(arr[fa], arr[idx]);fa = idx;} else {break;}} // while loop}
};
} // namespace lotusclass SeatManager {lotus::Heap<int> heap;// std::priority_queue<int, vector<int>, greater<int>> heap;public:SeatManager(int n) {for (int i = 1; i <= n; i += 1) {heap.push(i);}}int reserve() {int ret = heap.top();heap.pop();return ret;}void unreserve(int seatNumber) {heap.push(seatNumber);}
};/*** Your SeatManager object will be instantiated and called as such:* SeatManager* obj = new SeatManager(n);* int param_1 = obj->reserve();* obj->unreserve(seatNumber);*/
⛰️C语言
座位预约管理系统 - 提交记录 - 力扣(LeetCode)
// [lotus - heap - begin]
typedef size_t size_type;
typedef int value_type;
typedef bool (*value_compare)(const value_type*, const value_type*);#define M (100000 + 10)bool less(const void* x, const void* y) {return *(value_type*)x < *(value_type*)y;
}void swap(value_type* x, value_type* y) {value_type tmp = *x;*x = *y;*y = tmp;
}void heapify(value_type* arr, int fa, int border, value_compare cmp) {assert(fa <= border);while ((fa << 1) + 1 <= border) {int left = (fa << 1) + 1;int right = (fa << 1) + 2;int idx = fa;if (left <= border && cmp(&arr[left], &arr[idx])) {idx = left;}if (right <= border && cmp(&arr[right], &arr[idx])) {idx = right;}if (idx != fa) {swap(&arr[fa], &arr[idx]);fa = idx;} else {break;}} // while loop
}// data struct
typedef struct {size_type size;value_type heap[M];value_compare cmp;
} Heap;// constructor & distructor
void heap_constructor(Heap* p) {p->size = 0;p->cmp = (value_compare)&less;
}void heap_distructor(Heap* p) {free(p);
}// Element access
value_type heap_top(Heap* p) {return p->heap[0];
}// Capacity
bool empty(Heap* p) {return 0 == p->size;
}
size_type size(Heap* p) {return p->size;
}// Modifiers
void heap_push(Heap* p, const value_type value) {p->heap[p->size] = value;p->size += 1;// 自底向上进行调整int i = p->size - 1;for (; i > 0 && p->cmp(&value, &p->heap[(i - 1) >> 1]); i = (i - 1) >> 1) {p->heap[i] = p->heap[(i - 1) >> 1];}p->heap[i] = value;
}void heap_pop(Heap* p) {value_type ret = p->heap[0];p->heap[0] = p->heap[p->size - 1];p->size += -1;if (p->size) {heapify(p->heap, 0, p->size - 1, p->cmp);}
}
// [lotus - heap - end]// [leetcode - Solution - begin]
typedef struct {Heap* heap;
} SeatManager;SeatManager* seatManagerCreate(int n) {SeatManager* p = (SeatManager*)malloc(sizeof(SeatManager));p->heap = (Heap*)malloc(sizeof(Heap));heap_constructor(p->heap);for (int i = 1; i <= n; i += 1) {heap_push(p->heap, i);}return p;
}int seatManagerReserve(SeatManager* obj) {int ret = heap_top(obj->heap);heap_pop(obj->heap);return ret;
}void seatManagerUnreserve(SeatManager* obj, int seatNumber) {heap_push(obj->heap, seatNumber);
}void seatManagerFree(SeatManager* obj) {heap_distructor(obj->heap);free(obj);
}
// [leetcode - Solution - end]/*** Your SeatManager struct will be instantiated and called as such:* SeatManager* obj = seatManagerCreate(n);* int param_1 = seatManagerReserve(obj);* seatManagerUnreserve(obj, seatNumber);* seatManagerFree(obj);
*/
⭐END
🌟交流方式
关注我,学习更多C/C++,python,算法,软件工程,计算机知识!
⭐交流方式⭐ |C/C++|算法|设计模式|软件架构-CSDN社区
B站
👨💻主页:天赐细莲 bilibili