Djkastra堆(手写堆)优化版

直接上代码
代码中的注释掉的部分为C++优先队列实现

#include<cstdio>
#include<cstdlib> 
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring> 
using namespace std;
typedef pair<int,int> PII; // first 存距离   second 存编号 
const int maxn = 2e5+10;
int n, m; // 村庄数,边数 
int cnt = 0;
int dist[maxn];
bool st[maxn]; // 第 i 个点的最短路是否确定,是否需要更新 
int head[maxn];
struct Edge {
	int to, next, w;
}e[maxn];

// ***** 小根堆 ************************************************************************************************** 
typedef struct node {
	int index;
	int len;
} Pos;

typedef struct HeapStruct {
	Pos *Element; // 存储堆元素的数组
	int Size; // 堆的当前元素个数(最后一个元素的下标)
	int MaxSize; // 堆的存储空间大小 
} HeapStruct, *MinHeap;

// 创建一个大小为MaxSize的堆 
MinHeap Create (int MaxSize) {
	MinHeap H = (MinHeap) malloc (sizeof(struct HeapStruct)); // 分配堆结构空间
	H->Element = (Pos *) malloc ((MaxSize + 1) * sizeof(Pos)); // 分配存储堆元素的数组的空间
	H->Size = 0;
	H->MaxSize = MaxSize; 
	H->Element[0].len = INT_MIN; // 数组的第一个元素放极小元素,数组第二个元素放堆中 

	return H; 
}

// 释放堆申请的空间 
void Destroy(MinHeap H) {
	free(H->Element); // 先释放堆结点的数组空间 
	free(H); // 再释放堆结点的空间 
}

// 判断小根堆是否为空
bool IsEmpty(MinHeap H) {
	return (H->Size == 0);
}

// 判断最小堆是否已满 
bool IsFull(MinHeap H) {
	return (H->Size == H->MaxSize); // 判断最小堆中的元素个数Size是否等于最大容量 
} 

// 将元素 item 插入最小堆 H 
void Insert(MinHeap H, Pos item) {
	int i = 0;
	
	// 判断堆 H 是否已满
	if (IsFull(H)) {
		printf("Heap is full\n");
		return ;
	} 
	
	/*
	如果H未满,将item放入堆最后一个元素,查看它的父节点,如果它的父节点比它大,将它和它的父节点互换位置,
  循环此过程,直至它的父节点小于它。可能它比所有它的父节点都要小,但是一定会比哨兵大(数组中下标为0的位置),
  所以一定最后它的下标一定大于哨兵的下标0。这就是哨兵的意义。
	*/
	H->Size++;
	for(i = H->Size; H->Element[i / 2].len > item.len; i = i / 2) {
		H->Element[i] = H->Element[i / 2];
	}
	H->Element[i] = item;
}

// 返回最小堆堆顶 
Pos Delete(MinHeap H) {
	int parent = 0, child = 0;
	Pos item, temp;
	
	if (IsEmpty(H)) {
		printf("Heap is Empty\n");
		return H->Element[0];
	}
	/*
	  堆没有空,将根节点返回,最后一个叶子节点放到根节点位置,然后比较它与它的左右子节点中最小
	  节点的大小,如果它比较大,则将它和它的较小的子节点互换位置,重复此过程,直至他比两个子节点
	  都小或者它不在有子节点
  	*/
  	item = H->Element[1];
  	temp = H->Element[H->Size];
  	H->Size--;
  	for(parent = 1; parent * 2 <= H->Size; parent = child) {
  		child = parent * 2;
  		// 找出左右结点最小的那个
		if(child != H->Size && (H->Element[child].len > H->Element[child + 1].len)) {
			child++;
		} 
		// 比较它与最小的子节点的大小,如果它比较大,则两者互换位置,否则跳出循环 
		if(temp.len > H->Element[child].len) {
			H->Element[parent] = H->Element[child];
		}
		else break;
	}
	H->Element[parent] = temp;
	return item;
}

// ***** 链式前向星 *********************************************************************************************** 
void add(int u, int v, int w) {
	e[++cnt].next = head[u];
	e[cnt].to = v;
	e[cnt].w = w;
	head[u] = cnt;
}

void init() {
	memset(dist, 0x3f3f3f3f, sizeof(dist)); // 将所有距离初始化为正无穷 
	memset(head, 0, sizeof(head));
	memset(e, 0, sizeof(e));
	cnt = 0;
}

// ***** DJ *************************************************************************************************** 
int dijkstra(int k) {
	dist[k] = 0; // 第一个点到起点的距离
	
//	priority_queue<PII, vector<PII>, greater<PII> > heap; // 小根堆 
	MinHeap H;
	H = Create(m); 
	
//	heap.push({0,k});
	Insert(H, {k, 0});
	
	while(!IsEmpty(H)) { // 堆不空 
//		PII t = heap.top();
		Pos t = Delete(H);
//		heap.pop();

		int ver = t.index, dis = t.len;
		if(st[ver]) continue; // 重边(访问过的)就不用再更新了,DJ思想就是贪心的访问每条最短边
		st[ver] =  true; // 标记 t 已经确定为最短路
		
		for(int i = head[ver]; i; i = e[i].next) {
			int to = e[i].to;
			if(dist[to] > dis + e[i].w) {
				dist[to] = dis + e[i].w;
//				heap.push({dist[to], to});
				Insert(H, {to, dist[to]});
			}
		}
	}
}

int main() {
	freopen("test3.in", "r", stdin);
	int k, p; // k为起点 p为终点
	while(~scanf("%d%d%d%d", &n, &m, &k, &p)) {
		init();
		for(int i = 1; i <= m; i++) {
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			add(u, v, w);
		}
		dijkstra(k);
		if(dist[p] != 0x3f3f3f3f) {
			printf("%d\n", dist[p]); // 到达目标的最短距离。 DJ计算一个起点,多个终点 
		}
		else printf("无法到达!\n");
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是Java实现的堆排序代码: ```java public class HeapSort { public void sort(int[] arr) { int n = arr.length; // 从最后一个非叶子节点开始构建最大堆 for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i); // 依次将堆顶元素移到数组末尾,并重新构建最大堆 for (int i = n - 1; i >= 0; i--) { // 将堆顶元素与当前未排序部分的最后一个元素交换 int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; // 重新构建最大堆 heapify(arr, i, 0); } } // 以根节点为i的子树为最大堆 void heapify(int[] arr, int n, int i) { int largest = i; int l = 2 * i + 1; // 左子节点 int r = 2 * i + 2; // 右子节点 // 如果左子节点比根节点大,则更新最大值 if (l < n && arr[l] > arr[largest]) largest = l; // 如果右子节点比最大值大,则更新最大值 if (r < n && arr[r] > arr[largest]) largest = r; // 如果最大值不是根节点,则交换根节点和最大值,并继续向下调整 if (largest != i) { int swap = arr[i]; arr[i] = arr[largest]; arr[largest] = swap; heapify(arr, n, largest); } } } ``` 在堆排序中,我们首先构建一个最大堆,然后依次将堆顶元素移到数组末尾,并重新构建最大堆。`heapify()`方法用于将以根节点为i的子树调整为最大堆,其中n表示当前堆的大小。在`heapify()`方法中,我们首先找到根节点、左子节点和右子节点中的最大值,如果最大值不是根节点,则交换根节点和最大值,并继续向下调整。在堆排序中,时间复杂度为O(nlogn),空间复杂度为O(1)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值