编程对于工科学生的重要性不言而喻,如果你喜欢这篇文章,欢迎一起交流学习!欢迎交流:[email protected]
写在前面:我写C写惯了。python总是会加分号,像强迫症一样,大家别介意啊。
本文主要记录最小堆,堆优化dijkstra在百度文库有另一个版本,id: geek595,均原创。
本文先给出基本最小堆排序,然后再给出堆优化dijkstra(大二写的代码,很丑也没修改,求别喷)。
堆排是一种非常高效的排序,可以用在dijkstra、prim等算法中,优化算法复杂度。
相比较于桶排,push与pop复杂度稍有提高,但是空间复杂度却非常合理。
堆排利用了完全二叉树的性质。完全二叉树常常用数组保存(下标从1开始)。
当前节点:i;
父节点: i / 2;
左子节点:2*i; 又子节点:2*i+1;
例如,下图转换为数组就是:
元素 | 3 | 8 | 4 | 9 | 10 | 12 | 9 | 11 | 13 |
下标 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
首先建立一个空堆,将元素插入进去。
如上图,假设此时C节点是我们要插入的节点。
这里我们还采用上面的二叉树图进行讲解。由堆的特性,根节点A为我们要删除的元素。
下面就是最激动人心的代码啦!
# -*- coding: utf-8 -*-
# Min Heap Sort
# Insert elements in the heap.
def heap_sort_push(myList):
# Because of complete binary trees' character,don't use the heap's first element.
heap = [-1];
for i in range(len(myList)):
t = i+1;
heap.append(myList[i]);
# Bubbling up
while heap[t] < heap[t//2]: # In python3, use '//' to replace '/'.
heap[t//2], heap[t] = heap[t], heap[(t)//2];
t = t//2;
return heap;
def find_smallest(x,y,t):
if x >= y:
return 2*t+1;
else:
return 2*t;
# Pop an element from the heap
def heap_sort_pop(heap):
popElement = heap[1];
# Move the first element and last one.
heap[1] = heap.pop(len(heap)-1);
# Bubbling down.
for i in range(len(heap)):
t = i+1;
if heap[t] > heap[t*2] or heap[t] > heap[t*2+1]:
s = find_smallest(heap[t*2],heap[t*2+1],t)
heap[t],heap[s] = heap[s],heap[t];
else:
return (popElement,heap);
myList = [11,3,8,10,9,13,12,4];
heap = heap_sort_push(myList);
print(heap[1:]);
(firstElement,heap) = heap_sort_pop(heap);
print(heap[1:]);
以上代码复制粘贴即可运行。效果:
#include
#include
#include
#include
using namespace std;
#define maxnum 1000
int link[maxnum][maxnum];//记录每个点的邻接边
int c[maxnum][maxnum]; //邻接矩阵
int A[maxnum],n;
struct node
{
int s;//起点
int e;//终点
int w;//权
};
typedef struct
{
int s[maxnum];
int e[maxnum];
int w[maxnum];
int length;
}nodee;
int top(nodee *l,int i)
{
if(i==1)
printf("(%d,%d)-%d\n",l->s[1],l->e[1],l->w[1]);
}
void insert_tail(nodee *l,int s,int e,int w)//插入新元素
{
int x,ts,te,tw,ww;
l->length=l->length+1;
l->s[l->length]=s;
l->e[l->length]=e;
l->w[l->length]=w;
/*开始向上冒泡*/
x=l->length;
while(x>1)
{
if(x/2==0)
continue;
if(l->w[x]w[x/2])
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x/2];
l->e[x]=l->e[x/2];
l->w[x]=l->w[x/2];
l->s[x/2]=ts;
l->e[x/2]=te;
l->w[x/2]=tw;
x=x/2;
}
else
break;
}
}
void d_elete(nodee *l)
{
int ts,te,tw,x,f1=0,f2=0,f3=0;
l->s[1]=l->s[l->length];
l->e[1]=l->e[l->length];
l->w[1]=l->w[l->length];
l->s[l->length]=65535;
l->e[l->length]=65535;
l->w[l->length]=65535;
l->length=l->length-1;
/*向下冒泡*/
x=1;
while((2*x)<=l->length)/*判断父亲和两个儿子的权重大小*/
{
if(l->w[x]>l->w[2*x+1]) f1=1;
if(l->w[x]>l->w[2*x]) f2=1;
if(l->w[2*x]>l->w[x*2+1]) f3=1;
if(f3==1&&f1==1&&f2==1)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2+1];
l->e[x]=l->e[x*2+1];
l->w[x]=l->w[x*2+1];
l->s[x*2+1]=ts;
l->e[x*2+1]=te;
l->w[x*2+1]=tw;
x=2*x+1;
}
if(f1==1&&f2==1&&f3==0)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2];
l->e[x]=l->e[x*2];
l->w[x]=l->w[x*2];
l->s[x*2]=ts;
l->e[x*2]=te;
l->w[x*2]=tw;
x=2*x;
}
if(f1==0&&f2==0)
break;
if(f1==0&&f2==1)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2];
l->e[x]=l->e[x*2];
l->w[x]=l->w[x*2];
l->s[x*2]=ts;
l->e[x*2]=te;
l->w[x*2]=tw;
x=2*x;
}
if(f1==1&&f2==0)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2+1];
l->e[x]=l->e[x*2+1];
l->w[x]=l->w[x*2+1];
l->s[x*2+1]=ts;
l->e[x*2+1]=te;
l->w[x*2+1]=tw;
x=2*x+1;
}
f1=0;f2=0;f3=0;
}
}
void dijkstra(int s)
{
int i,total;
int vis[maxnum];//用来标记节点已访问
memset(vis,0,sizeof(vis));//将vis中成员标记为0
struct node nn;
nodee heap;//建立堆
heap.length=0;
memset(heap.w,65535,sizeof(heap.w));
memset(heap.s,65535,sizeof(heap.s));
memset(heap.e,65535,sizeof(heap.e));
total = 1;//统计已经加入的节点数
vis[s] = 1;//初始化第一个节点为已探索
while(total < n)
{
for(i=1;i>n>>line;
for(i=1;i<=n;i++)
link[i][0] = 1;
for(i=1;i<=line;i++)
{
cin>>p>>q>>len;
c[p][q] = c[q][p] = len;
link[p][link[p][0]++] = q;
link[q][link[q][0]++] = p;
}
cout<<"s:"<>i;
A[i]=0;
dijkstra(i);//以源节点为起点
while(1)
{
cout<<"e:"<>i;
if(i==0)
break;
cout<<"w:"<
#include
#include
#include
#include
using namespace std;
#define maxnum 1000
int link[maxnum][maxnum];//记录每个点的邻接边
int c[maxnum][maxnum]; //邻接矩阵
int A[maxnum],n;
struct node
{
int s;//起点
int e;//终点
int w;//权
};
typedef struct
{
int s[maxnum];
int e[maxnum];
int w[maxnum];
int length;
}nodee;
int top(nodee *l,int i)
{
if(i==1)
printf("(%d,%d)-%d\n",l->s[1],l->e[1],l->w[1]);
}
void insert_tail(nodee *l,int s,int e,int w)//插入新元素
{
int x,ts,te,tw,ww;
l->length=l->length+1;
l->s[l->length]=s;
l->e[l->length]=e;
l->w[l->length]=w;
/*开始向上冒泡*/
x=l->length;
while(x>1)
{
if(x/2==0)
continue;
if(l->w[x]w[x/2])
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x/2];
l->e[x]=l->e[x/2];
l->w[x]=l->w[x/2];
l->s[x/2]=ts;
l->e[x/2]=te;
l->w[x/2]=tw;
x=x/2;
}
else
break;
}
}
void d_elete(nodee *l)
{
int ts,te,tw,x,f1=0,f2=0,f3=0;
l->s[1]=l->s[l->length];
l->e[1]=l->e[l->length];
l->w[1]=l->w[l->length];
l->s[l->length]=65535;
l->e[l->length]=65535;
l->w[l->length]=65535;
l->length=l->length-1;
/*向下冒泡*/
x=1;
while((2*x)<=l->length)/*判断父亲和两个儿子的权重大小*/
{
if(l->w[x]>l->w[2*x+1]) f1=1;
if(l->w[x]>l->w[2*x]) f2=1;
if(l->w[2*x]>l->w[x*2+1]) f3=1;
if(f3==1&&f1==1&&f2==1)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2+1];
l->e[x]=l->e[x*2+1];
l->w[x]=l->w[x*2+1];
l->s[x*2+1]=ts;
l->e[x*2+1]=te;
l->w[x*2+1]=tw;
x=2*x+1;
}
if(f1==1&&f2==1&&f3==0)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2];
l->e[x]=l->e[x*2];
l->w[x]=l->w[x*2];
l->s[x*2]=ts;
l->e[x*2]=te;
l->w[x*2]=tw;
x=2*x;
}
if(f1==0&&f2==0)
break;
if(f1==0&&f2==1)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2];
l->e[x]=l->e[x*2];
l->w[x]=l->w[x*2];
l->s[x*2]=ts;
l->e[x*2]=te;
l->w[x*2]=tw;
x=2*x;
}
if(f1==1&&f2==0)
{
ts=l->s[x];
te=l->e[x];
tw=l->w[x];
l->s[x]=l->s[x*2+1];
l->e[x]=l->e[x*2+1];
l->w[x]=l->w[x*2+1];
l->s[x*2+1]=ts;
l->e[x*2+1]=te;
l->w[x*2+1]=tw;
x=2*x+1;
}
f1=0;f2=0;f3=0;
}
}
void dijkstra(int s)
{
int i,total;
int vis[maxnum];//用来标记节点已访问
memset(vis,0,sizeof(vis));//将vis中成员标记为0
struct node nn;
nodee heap;//建立堆
heap.length=0;
memset(heap.w,65535,sizeof(heap.w));
memset(heap.s,65535,sizeof(heap.s));
memset(heap.e,65535,sizeof(heap.e));
total = 1;//统计已经加入的节点数
vis[s] = 1;//初始化第一个节点为已探索
while(total < n)
{
for(i=1;i>n>>line;
for(i=1;i<=n;i++)
link[i][0] = 1;
for(i=1;i<=line;i++)
{
cin>>p>>q>>len;
c[p][q] = c[q][p] = len;
link[p][link[p][0]++] = q;
link[q][link[q][0]++] = p;
}
//cout<<"s:"<>i;
i=1;
A[i]=0;
tic=clock();
for(int j=0;j<10000;j++)
dijkstra(i);//以源节点为起点
toc=clock();
cout<>i;
if(i==0)
break;
cout<<"w:"<