对于一个有向无权的图,我们只需从起点开始,依次往后寻找即可,这还谈不上算法,只能说是一种思想,这种思想解释如下:
首先对于一个有向无权的图:
我们令v0为起点,v0到v0的路径为0,所有在v0下面标0,如下图所示:
接着发现v0到v1和v2,v3都只需经过一条边,因此在v1和v2,v3下面标1,如下图所示:
接着找v1和v2,v3相邻的点,发现是v2和v4,v6,就在这两个点下面标2.如下图所示:
没有点剩下,整个过程完毕,如果还剩下点,就继续按照上面的思想执行,直到所有的点都遍历到。
这样整个过程就完了,点下面标的数字就是所需要的最短的路径,把上述思想转换成代码就可以了。
代码如下:
#include <iostream>
using namespace std;
#define Inf 65535
//列队的相关定义//
typedef struct QueueRecord *Queue;
#define MinQueueSize 10
struct QueueRecord
{
int Capacity; //队的容量
int Front; //队头
int Rear; //队尾
int Size; //队中元素的个数
int *Array; //数组
};
/邻接表的相关定义//
typedef struct EdgeNode *position;
typedef struct Led_table* Table;
struct EdgeNode //边表结点
{
int adjvex; // 邻接点域,存储该顶点对应的下标
int weight; // 对应边的权值
position next; // 链域,指向下一个邻接点
};
struct Led_table // 邻接表结构
{
int data; //邻接表的大小
position *firstedge; //边表头指针,可以理解为数组
};
///列队相关函数声明
int IsEmpty(Queue Q); //判断队列是否为空
int IsFull(Queue Q); //判断队列是否满了
void MakeEmpty(Queue Q); //构造一个空列队
Queue CreateQueue(int MaxElements); //创建一个列队
void DisposeQueue(Queue Q); //释放一个列队
void Enqueue(int x, Queue Q); //入队
int Dequeue(Queue Q); //出队
int Front(Queue Q); //返回队首值,不出队
///列队相关函数定义
int IsEmpty(Queue Q)
{
return Q->Size == 0;
}
int IsFull(Queue Q)
{
if(Q->Size > Q->Capacity )
{
cout << "queue full" << endl;
return -1;
}
else
{
return 0;
}
}
void MakeEmpty(Queue Q)
{
Q->Size = 0;
Q->Front = 1;
Q->Rear = 0;
}
Queue CreateQueue(int MaxElements)
{
Queue Q;
if (MaxElements < MinQueueSize)
{
cout << "queue size is too small" << endl;
}
Q = static_cast<Queue> (malloc(sizeof(struct QueueRecord)));
if(Q == NULL)
{
cout << "out of space!!!";
}
Q->Array =static_cast<int*>(malloc(sizeof(int)*MaxElements));
if(Q->Array == NULL)
{
cout << "out of space!!!";
}
Q->Capacity = MaxElements;
MakeEmpty(Q);
return Q;
}
void DisposeQueue(Queue Q)
{
if (Q != NULL)
{
free(Q->Array );
free(Q);
}
}
static int Succ(int Value, Queue Q) //循环数组,用于回绕
{
if(++Value == Q->Capacity )
Value = 0;
return Value;
}
void Enqueue(int x, Queue Q)
{
if(IsFull(Q))
{
cout << "Full queue" << endl;
}
else
{
Q->Size ++;
Q->Rear = Succ(Q->Rear, Q);
Q->Array [Q->Rear] = x;
}
}
int Dequeue(Queue Q)
{
if(IsEmpty(Q))
{
cout << "Empty Queue" << endl;
return false; //仅表示错误
}
else
{
Q->Size --;
Q->Front = Succ(Q->Front, Q);
return Q->Array[(Q->Front)-1];
}
}
int Front(Queue Q)
{
if(IsEmpty(Q))
{
cout << "Empty Queue" << endl;
return false; //仅表示错误
}
else
return Q->Array[Q->Front];
}
//邻接表相关函数定义///
Table Creat_Lable (int MaxElements) //MaxElements参数为希望创建的节点数
{
Table table1 = static_cast<Table> (malloc(sizeof(struct Led_table)));
table1->data = MaxElements;
if (table1 == NULL)
{
cout << "out of space!!!";
}
table1->firstedge = static_cast<position*>(malloc(sizeof(position)*(table1->data)));
if (table1->firstedge == NULL)
{
cout << "out of space!!!";
}
//给每个表头赋值,从0开始
for (int i = 0; i <= table1->data - 1; ++i)
{
table1->firstedge [i] = static_cast<position>(malloc(sizeof(position))); //申请一个节点
if (table1->firstedge [i] == NULL)
{
cout << "out of space!!!";
}
table1->firstedge [i]->adjvex = 0; //表头这个参数存储入度
table1->firstedge [i]->weight = 0; //此参数在此时没有意义
table1->firstedge [i]->next = NULL;
}
return table1;
}
void Insert (Table table1, int v, int w, int weig) //表示存在一条边为<v,w>,且权重为weig
{
position p = static_cast<position>(malloc(sizeof(position))); //申请一个节点
if(p == NULL)
{
cout << "out of space!!!";
}
p->adjvex = w;
p->weight = weig;
p->next = table1->firstedge [v]->next;
table1->firstedge [v]->next = p;
}
void CountIndegree(Table table1) //计算顶点的入度,存在头结点中
{
for(int i = 0; i <= table1->data - 1; ++i)
{
position p = table1->firstedge [i]->next;
while (p != NULL)
{
++(table1->firstedge [p->adjvex]->adjvex) ;
p = p->next;
}
}
}
int* Topsort(Table table1) //拓扑排序
{
Queue queue_1 = CreateQueue(15); //创建一个列队
int Counter = 0;
int *TopNum = static_cast<int*>( malloc (sizeof(int)*(table1->data ))); //此数组用来存储结果
int v;
for(int i = 0; i != table1->data; ++i)
{
if(table1->firstedge[i]->adjvex == 0)
{
Enqueue(i,queue_1); //如果顶点i的入度为0,就入队
}
}
while(!IsEmpty(queue_1))
{
v = Dequeue(queue_1);
TopNum[v] = ++Counter; //若TopNum[5] = 3, 则排第三的为v5
position p = table1->firstedge [v]->next;
while (p != NULL) //把这个节点删除后,更新入度
{
--(table1->firstedge [p->adjvex]->adjvex);
if(table1->firstedge [p->adjvex]->adjvex == 0) Enqueue(p->adjvex,queue_1);
p = p->next;
}
}
if(Counter != table1->data )
{
cout << "the graph has a cycle" << endl;
}
DisposeQueue(queue_1);
return TopNum;
}
void print_Topsort_result(int *TopNum,Table table1) //打印拓扑排序结果
{
for(int i = 1; i != table1->data+1 ; ++i)
{
for (int j = 0; j != table1->data ; ++j)
{
if (TopNum[j] == i)
{
if(i == table1->data)
{
cout << "v" << j;
}
else
{
cout << "v" << j << "->";
}
}
}
}
cout << endl;
}
/单源无权算法相关定义/
typedef struct unweight_path *unweight_node ;
struct unweight_path //
{
bool know;
int dist; // 邻接点域,存储该顶点对应的下标
int path; // 对应边的权值
};
unweight_node unweight_init(Table table1, int start) //节点初始化
{
unweight_node Node = static_cast<unweight_node>(malloc(sizeof(unweight_path)*(table1->data)));
if (Node == NULL)
{
cout << "out of space!!!";
}
for(int i = 0; i != table1->data; ++i)
{
Node[i].know = false;
Node[i].dist = Inf;
Node[i].path = 0;
}
Node[start].dist = 0;
return Node;
}
单源无权最短路径一般算法,时间复杂度较高
void Unweighted(Table table1,unweight_node Node)
{
int currDist;
int v;
for(currDist = 0;currDist != table1->data; ++currDist)
{
for(v = 0; v != table1->data; ++v )
{
if(!Node[v].know && Node[v].dist == currDist )
{
Node[v].know = true;
position p = table1->firstedge [v]->next;
while (p != NULL) //与这个节点有连接的距离+1
{
if(Node[p->adjvex].dist == Inf)
{
Node[p->adjvex].dist = currDist+1;
Node[p->adjvex].path = v;
}
p = p->next;
}
}
}
}
}
单源无权最短路径改进算法/
void Unweighted_change (Table table1,unweight_node Node)
{
int v;
Queue queue_1 = CreateQueue(15); //创建一个列队
for(int i = 0; i != table1->data; ++i)
{
if(Node[i].dist == 0)
{
Enqueue(i,queue_1);
}
}
while(!IsEmpty(queue_1))
{
v = Dequeue(queue_1);
Node[v].know = true;
position p = table1->firstedge [v]->next;
while (p != NULL) //与这个节点有连接的距离+1
{
if(Node[p->adjvex].dist == Inf)
{
Node[p->adjvex].dist = Node[v].dist +1;
Node[p->adjvex].path = v;
Enqueue(p->adjvex,queue_1);
}
p = p->next;
}
}
DisposeQueue(queue_1);
}
int main ()
{
Table table_1 = Creat_Lable (7); //创建一个大小为7的邻接表
//根据图来为邻接表插入数据
Insert (table_1, 0, 1, 2);Insert (table_1, 0, 2, 4);Insert (table_1, 0, 3, 1);
Insert (table_1, 1, 3, 3);Insert (table_1, 1, 4, 10);
Insert (table_1, 2, 5, 5);
Insert (table_1, 3, 2, 2);Insert (table_1, 3, 5, 8);Insert (table_1, 3, 6, 4);
Insert (table_1, 4, 3, 2);Insert (table_1, 4, 6, 6);
Insert (table_1, 6, 5, 1);
/测试
unweight_node Node_1 = unweight_init(table_1, 0);
Unweighted(table_1, Node_1);
for (int i = 0; i != table_1->data; ++i)
{
cout << Node_1[i].dist << '\t';
}
cout << endl;
Unweighted_change (table_1, Node_1);
for (int i = 0; i != table_1->data; ++i)
{
cout << Node_1[i].dist << '\t';
}
cout << endl;
while(1);
return 0;
}
图放在邻接表中。
上述代码提出了两种方法,区别在于一种用了两次for循环,时间复杂度比较高,另一种采用了列队数据结构,时间复杂度要低,但是两次的结果都一样,如下图所示:
这种方法还是不错的,主要是要善于使用数据结构。
夜深了,,,要下雨了。