有向无权图的最短路径算法

    对于一个有向无权的图,我们只需从起点开始,依次往后寻找即可,这还谈不上算法,只能说是一种思想,这种思想解释如下:

 

    首先对于一个有向无权的图:

    我们令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循环,时间复杂度比较高,另一种采用了列队数据结构,时间复杂度要低,但是两次的结果都一样,如下图所示:

 

    这种方法还是不错的,主要是要善于使用数据结构。

 

    夜深了,,,要下雨了。

 

转载于:https://www.cnblogs.com/1242118789lr/p/6748075.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值