堆的实现(手写堆

堆其实就是一个完全二叉树
堆分成大顶堆和小顶堆,大顶堆:节点的值 >= 其左孩子的值 且 >= 右孩子的值,对于所有节点成立。小顶堆相反。

关于建堆初始编号造成的困惑

如果根节点编号是 0,那么:

  • i 节点的父节点:(i-1)/2
  • i 节点的左孩子:i * 2 + 1
  • i 节点的右孩子:i * 2 + 2

如果根节点编号是 1,那么:

  • i 节点的父节点:i / 2
  • i 节点的左孩子:i * 2
  • i 节点的右孩子:i * 2 + 1

在这里插入图片描述

学习博客
初始化一个小顶堆
节点 i i i 的两个子节点编号为 2 ∗ i 2*i 2i 2 ∗ i + 1 2*i+1 2i+1
所以节点 i i i 除以 2 2 2 即可得到它的父节点
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int heap[maxn];

void up(int i){// 上调编号位i的节点
	if(i == 1) return;
	while(i != 1){
		if(heap[i] < heap[i / 2]) swap(heap[i], heap[i / 2]);
		else break;
		i /= 2;
	}
}
void work()
{
	cin >> n;
	for(int i = 1; i <= n; ++i){
		int x;cin >> x;
		heap[i] = x;//插入尾部
		up(i);// 上调
	}
	for(int i = 1; i <= n; ++i){
		cout << heap[i] << " ";
	}
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

L2-012 关于堆的判断 (25 分)
思路:
手写堆
题解
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 1e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int heap[maxn];
map <int, int> id;// 权值映射为堆里的编号

void up(int i){
	if(i == 1) return;
	while(i != 1){
		if(heap[i] < heap[i / 2]) swap(heap[i], heap[i / 2]);
		else break;
		i /= 2;
	}
}
void work()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i){
		int x;cin >> x;
		heap[i] = x;
		up(i);
	}
	for(int i = 1; i <= n; ++i)	id[heap[i]] = i;
	while(m--){
		int x, y;cin >> x;
		string s;cin >> s;
		if(s[0] == 'a'){
			cin >> y >> s >> s;
			if(id[x] / 2 == id[y] / 2) cout << "T\n";
			else cout << "F\n";
		}
		else{
			cin >> s;
			if(s[0] == 'a'){
				cin >> s >> s >> y;
				if(id[y] == id[x] / 2) cout << "T\n";
				else cout << "F\n";
			}
			else{
				cin >> s;
				if(s[0] == 'r'){
					if(id[x] == 1) cout << "T\n";
					else cout << "F\n";
				}
				else{
					cin >> s >> y;
					if(id[x] == id[y] / 2) cout << "T\n";
					else cout << "F\n";
				}
			}
		}
	}
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}
<think>好的,我现在需要帮助用户理解如何用Python手动实现数据结构。首先,我得回忆一下的基本概念和特性。通常是一个完全二叉树,分为最大堆和最小两种类型。最大堆的每个父节点都大于或等于其子节点,而最小则相反。的常见操作包括插入元素、删除顶元素以及化(调整结构以保持其性质)。 接下来,我需要考虑如何在Python中表示。通常,可以用数组来实现,因为完全二叉树的特性使得可以用数组索引来表示父节点和子节点的关系。比如,对于索引i的节点,其左子节点在2i+1,右子节点在2i+2,父节点在(i-1)//2的位置。 然后,我需要确定实现的关键方法,比如插入和提取操作。插入元素时,需要将新元素添加到数组末尾,然后通过上浮操作(sift up)调整其位置,直到的性质恢复。提取顶元素(比如最大值或最小值)时,需要将顶元素与末尾元素交换,移除末尾元素,然后对新的顶元素执行下沉操作(sift down)以维持结构。 用户提到的排序可能相关,但这里重点是实现数据结构本身。我需要确保代码示例中的sift_down函数正确实现下沉操作,以及插入和提取方法正确维护结构。同时,需要解释每个步骤的作用,比如建的过程和如何调整。 另外,考虑到用户提供的引用[4]中提到了排序的实现,我需要确保我的实现与之兼容,但专注于数据结构本身而非排序算法。可能需要引用相关内容来说明的应用,比如排序是如何利用结构的。 最后,生成相关问题时要涵盖的应用、优化、时间复杂度以及与其他数据结构的比较,帮助用户进一步学习。需要检查引用是否正确,比如引用[4]关于排序的步骤,是否在回答中正确引用。</think>### 如何用Python从零实现数据结构(Heap)是一种基于完全二叉树的数据结构,分为最大堆(父节点值 ≥ 子节点值)和最小(父节点值 ≤ 子节点值)。以下是Python实现的核心步骤: --- #### 1. **的存储结构与初始化** 通常用数组实现,利用完全二叉树的特性: - 父节点索引为 $i$,左子节点为 $2i+1$,右子节点为 $2i+2$ - 子节点索引为 $i$,父节点为 $\lfloor (i-1)/2 \rfloor$ ```python class MaxHeap: def __init__(self): self.heap = [] ``` --- #### 2. **核心操作:上浮与下沉** - **上浮(sift_up)**:插入元素后调整结构 - **下沉(sift_down)**:删除元素后调整结构 ```python def sift_down(self, idx): max_idx = idx left = 2 * idx + 1 right = 2 * idx + 2 n = len(self.heap) # 比较父节点与子节点的大小 if left < n and self.heap[left] > self.heap[max_idx]: max_idx = left if right < n and self.heap[right] > self.heap[max_idx]: max_idx = right if max_idx != idx: self.heap[idx], self.heap[max_idx] = self.heap[max_idx], self.heap[idx] self.sift_down(max_idx) def sift_up(self, idx): parent = (idx - 1) // 2 if parent >= 0 and self.heap[idx] > self.heap[parent]: self.heap[idx], self.heap[parent] = self.heap[parent], self.heap[idx] self.sift_up(parent) ``` --- #### 3. **插入与删除操作** - **插入元素**:添加到末尾,触发上浮 - **提取最大值**:交换顶与末尾元素,删除后触发下沉 ```python def insert(self, val): self.heap.append(val) self.sift_up(len(self.heap) - 1) def extract_max(self): if not self.heap: return None max_val = self.heap[0] self.heap[0] = self.heap[-1] self.heap.pop() self.sift_down(0) return max_val ``` --- #### 4. **建与时间复杂度** - **建**:从最后一个非叶子节点开始依次下沉,时间复杂度为 $O(n)$ - **插入/删除**:单次操作时间复杂度为 $O(\log n)$ --- #### 应用场景 常用于优先队列、排序(如引用[4]所述)、Top K问题等场景[^4]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值