#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
//定义结构体
struct node{
int d_num;//跳数
int d_next;//下一跳节点
};
//定义链路状态算法的结构体
struct lsnode{
int visited;//1代表已访问
char path[40];//路径
int index;//路径字符数量
}lsn[40];
int main(){
struct node no_1[40][40], no_2[40][40];
int N=0,num=0;
int flag=0;//是否有节点出现,链路状态路由算法在所有节点都已经访问完成or找到目标节点的最短路径的时候结束
int f1=0,f2=1,f3=0;//是否满足交换条件的标志
int i=0,j=0,k=0,r=0,rl=0,m=0,n=0;
int min=0;//寻找权值最小的节点
int temp;
int quan;
char begin,end;
int beginNode=0,endNode=0;
char map[40][40];//坐标图
int node[50][2];//节点的坐标,最多100个节点,0横坐标、1纵坐标
int nearNodes[40][2];//2个相邻节点保存在数组
int nearnum=0;//相邻节点数组的大小
int topmap[40][40];//双向图二维表
struct node *routeHeaders[40];//保存每个链表的头指针
struct node *copyHeaders[40];//复制每个链表的头指针
typedef struct node* np;//开辟节点内存用到
struct node *p, *p1, *p2, *p3, *p4, *p5;//添加节点用到
//初始化40*40的地图
for(i=0;i<40;i++){
for(j=0;j<40;j++){
map[i][j]='*';
//printf("* ");
if(i != j)topmap[i][j]=10000;
else topmap[i][j]=0;
}
//printf("\n");
}
printf("请输入节点数量:\n");
scanf("%d",&N);
//随机生成坐标
srand(time(NULL));
for(i=0;i<N;i++){
node[i][0]=rand(i+1)%40;
node[i][1]=rand(i+10)%40;
//printf("%c ",i+1);
}
//printf("%d %d",node[0][0],node[0][1]);
//printf("%d %d",node[6][0],node[6][1]);
//printf("%d %d",node[6][0],node[6][1]);
//打印有节点的坐标图,
for(i=0;i<40;i++){
for(j=0;j<40;j++){
for(k=0;k<N;k++){
if(i==node[k][0] && j==node[k][1]){
flag=1;//有节点出现在这个坐标
printf("%c ",(char)(k+65));
break;
}
}
if(flag==1){
flag=0;
}else{
printf("* ");
}
}
printf("\n");
}
//打印连接情况
//while(1){
printf("请输入节点信号覆盖半径:\n");
scanf("%d",&r);
//printf("节点--------直线距离----------节点\n");
k=0;
for(i=0;i<N;i++){
for(j=i+1;j<N;j++){
//(x1-x1)的平方+(y1-y2)的平方<=r*r
rl=(node[i][0]-node[j][0])*(node[i][0]-node[j][0])+(node[i][1]-node[j][1])*(node[i][1]-node[j][1]);
if(rl <= r*r){//保存相邻信息,这里是相邻节点数组
nearNodes[k][0]=i;
nearNodes[k][1]=j;
k++;
nearNodes[k][0]=j;
nearNodes[k][1]=i;
k++;
//printf(" %c-------------%d--------------%c\n",(char)(65+i),(int)(sqrt(rl*1.0)),(char)(65+j));
topmap[i][j]=(int)(sqrt(rl*1.0));
topmap[j][i]=(int)(sqrt(rl*1.0));
}
}
nearNodes[k][0]=100;//结束标志
nearNodes[k][1]=100;
nearnum=k;//保存相邻节点的个数
//printf("\n");
}
//}
//打印最佳路径
getchar();
printf("请输入起始节点:\n");
scanf("%c",&begin);
beginNode=(int)begin;
//printf("%d\n",beginNode);
getchar();
printf("请输入终点节点:\n");
scanf("%c",&end);
endNode=(int)end;
//printf("%d\n",endNode);
printf("\n\n***********************距离矢量路由算法*******************************\n\n");
//初始化结构体二维数组
for(i=0;i<40;i++){
for(j=0;j<40;j++){
no_1[i][j].d_num=100;//跳数,头节点
no_1[i][j].d_next=100;//下一跳,头节点
//printf("%d %d %d\n",no_1[i][j].d_node,no_1[i][j].d_num,no_1[i][j].d_next);
no_2[i][j].d_num=100;//跳数,头节点
no_2[i][j].d_next=100;//下一跳,头节点
}
}
//根据相邻节点数组,初始化邻居相关的目的地、跳数、下一跳
for(i=0;i<nearnum;i++){
no_1[nearNodes[i][0]][nearNodes[i][1]].d_num=1;//【源下标】【邻居下标】
no_1[nearNodes[i][0]][nearNodes[i][1]].d_next=95;//下一跳,95直接交付
}
/*
//打印数组
printf("起始节点 终点节点 跳数 下一跳节点(第一次找到邻居)\n");
for(i=0;i<40;i++){
for(j=0;j<40;j++){
if(no_1[i][j].d_num != 100 && no_1[i][j].d_next != 100){
printf(" %c\t\t%c\t\t%d\t%c\n",(char)(65+i),(char)(65+j),no_1[i][j].d_num,(char)(no_1[i][j].d_next));
}
}
}
*/
//备份数组,进行相关的修改
for(i=0;i<40;i++){
for(j=0;j<40;j++){
if(no_1[i][j].d_num != 100 && no_1[i][j].d_next != 100){
no_2[i][j].d_num=no_1[i][j].d_num+1;//跳数+1
no_2[i][j].d_next=i+65;//下一跳改为自己的下标
}
}
}
/*
//打印表头指针备份数组
printf("起始节点 终点节点 跳数 下一跳节点(备份)\n");
for(i=0;i<40;i++){
for(j=0;j<40;j++){
if(no_2[i][j].d_num != 100 && no_2[i][j].d_next != 100){
printf(" %c\t\t%c\t\t%d\t%c\n",(char)(65+i),(char)(65+j),no_2[i][j].d_num,(char)(no_2[i][j].d_next));
}
}
}
*/
while(f3==0){//当没有改动时,结束交换信息的循环
num++;
f3=1;//若无改变,则结束循环
//遍历相邻节点数组,下标0本节点,1相邻节点,交换信息
//让0的实际数组根据1的备份数组来改动
for(i=0;i<nearnum;i++){//遍历相邻节点数组,实际数组no_1[nearNodes[i][0]][k],备份数组no_2[nearNodes[i][1]][j]
for(j=0;j<40;j++){//逐条使用备份数组no_2[nearNodes[i][1]][j]
if(no_2[nearNodes[i][1]][j].d_num != 100 && no_2[nearNodes[i][1]][j].d_next != 100){//若这个备份数组元素是有效的
for(k=0;k<40;k++){//逐条使用实际数组no_1[nearNodes[i][0]][k]
if(no_1[nearNodes[i][0]][k].d_num != 100 && no_1[nearNodes[i][0]][k].d_next != 100){//若这个实际数组元素是有效的
if(j==k){//若目的地一样
f1=1;//存在一个实际数组元素的目的地跟备份数组元素的目的地一样
//若副本数组的下一跳是邻居节点自己 && 实际数组下一跳不是邻居节点 && 实际数组下一跳不是95
if(no_2[nearNodes[i][1]][j].d_next==nearNodes[i][1] && no_1[nearNodes[i][0]][k].d_next!=nearNodes[i][1] && no_1[nearNodes[i][0]][k].d_next!=95){
//则更新实际数组
f3=0;//0表示有改动
no_1[nearNodes[i][0]][k].d_num = no_2[nearNodes[i][1]][j].d_num;
no_1[nearNodes[i][0]][k].d_next = no_2[nearNodes[i][1]][j].d_next;
}
//若副本数组的下一跳不是邻居节点自己,且实际数组元素的跳数大于备份数组元素的跳数
if(no_2[nearNodes[i][1]][j].d_next!=nearNodes[i][1] && no_1[nearNodes[i][0]][k].d_num > no_2[nearNodes[i][1]][j].d_num){
//则更新实际数组
f3=0;//0表示有改动
no_1[nearNodes[i][0]][k].d_num = no_2[nearNodes[i][1]][j].d_num;
no_1[nearNodes[i][0]][k].d_next = no_2[nearNodes[i][1]][j].d_next;
}
}
}
}//for k
//若目的地不一样(该实际数组元素无效,且备份数组元素有效),且备份数组元素的目的地不是实际数组元素下标
// && 实际数组的元素不可以是直接交付 && 实际数组的元素必须是还没被用上的
if(j!=k && j!=nearNodes[i][0] && no_1[nearNodes[i][0]][j].d_next!=95 && no_1[nearNodes[i][0]][j].d_num==100){
//则把该副本数组元素添加到实际数组元素,
//printf("改变%d %d\n",no_1[nearNodes[i][0]][j].d_num,no_1[nearNodes[i][0]][j].d_next);
f3=0;//0表示有改动
no_1[nearNodes[i][0]][j].d_num = no_2[nearNodes[i][1]][j].d_num;
no_1[nearNodes[i][0]][j].d_next = no_2[nearNodes[i][1]][j].d_next;
}
}
}//for j
}//for i
//备份数组,进行相关的修改
for(i=0;i<40;i++){
for(j=0;j<40;j++){
if(no_1[i][j].d_num != 100 && no_1[i][j].d_next != 100){
no_2[i][j].d_num=no_1[i][j].d_num+1;//跳数+1
no_2[i][j].d_next=i+65;//下一跳改为自己的下标
}else{
no_2[i][j].d_num=100;//跳数100
no_2[i][j].d_next=100;//下一跳100
}
}
}
}//while
//打印数组
printf("起始节点 终点节点 跳数 下一跳节点(交换次数:%d)\n",num);
for(i=0;i<40;i++){
for(j=0;j<40;j++){
if(no_1[i][j].d_num != 100 && no_1[i][j].d_next != 100){
printf(" %c\t\t%c\t\t%d\t%c\n",(char)(65+i),(char)(65+j),no_1[i][j].d_num,(char)(no_1[i][j].d_next));
}
}
}
//打印路径
printf("\n开始节点:%c\t结束节点:%c\n\n",(char)(beginNode),(char)(endNode));
f2=0;
f3=beginNode;
if(no_1[f3-65][endNode-65].d_next == 100) printf("%c-->%c没有路径可走",(char)(beginNode),(char)endNode);
else if(no_1[f3-65][endNode-65].d_next == 95) printf("%c-->%c",(char)(beginNode),(char)endNode);
else{
while(f3 != 95){
f2++;
if(no_1[f3-65][endNode-65].d_next == 95) break;
if(f2==1) printf("%c-->%c",(char)f3,(char)no_1[f3-65][endNode-65].d_next);
else printf("-->%c",(char)no_1[f3-65][endNode-65].d_next);
f3=no_1[f3-65][endNode-65].d_next;
}
printf("-->%c",(char)endNode);
//else printf("%c-->%c没有路径可走",(char)(beginNode),(char)endNode);
}
printf("\n\n\n");
printf("\n***********************链路状态路由算法*******************************\n\n");
printf("拓扑图转换为二维表\n");
printf(" ");
for(i=0;i<N;i++){
printf(" %c",(char)(65+i));//列头
}
printf("\n");
for(i=0;i<N;i++){
printf("%c",(char)(65+i));//行头
for(j=0;j<N;j++){
if(topmap[i][j]==10000) printf(" -");
else printf(" %d",topmap[i][j]);
}
printf("\n");
}
//printf("\n\n318\n\n");
//初始化节点数组
for(j=0;j<40;j++){
lsn[j].visited=0;//访问标志
for(i=0;i<40;i++){
lsn[j].path[i]=NULL;//路径
}
lsn[j].path[0]=(char)beginNode;//把起始节点保存到每个节点的路径数组开始
lsn[j].index =1;//路径字符数量
}
//在所有节点都已经访问完成or找到目标节点的最短路径的时候结束
while(min!=20000){
min=20000;//若min无变化,则循环结束
for(j=0;j<N;j++){//逐个使用begin这一行的元素(权值)
//begin这一行权值最小 && 节点访问标志是0的节点 && 权值不是0(0表示节点到自己)
if(topmap[beginNode-65][j] < min && lsn[j].visited==0 && topmap[beginNode-65][j] != 0){
min = topmap[beginNode-65][j];//选出最小值
temp=j;//记录下标
}
}//获得权值最小的节点
//if(min == 20000) break;//若全部节点都被访问
//若min是10000,访问到不可直接到达路径
if(min==10000){//该节点是不可以直接到达的点
lsn[temp].visited=1;//该节点被访问
lsn[temp].path[lsn[temp].index]=(char)(temp+65);//该节点的路径加入该节点
lsn[temp].index++;//路径元素数量+1
}else{//该节点是可以直接到达的点
lsn[temp].visited=1;//该节点被访问
lsn[temp].path[lsn[temp].index]=(char)(temp+65);//该节点的路径加入该节点
lsn[temp].index++;//路径元素数量+1
for(j=0;j<N;j++){//逐个使用temp这一行的元素(权值)
//temp这一行找到出度(权值比begin这一行的权值要小 && begin的这个节点未被访问过 && temp这一行的出度节点不可以是自己)
if(topmap[temp][j]<topmap[beginNode-65][j] && lsn[j].visited==0 && temp != j){
topmap[beginNode-65][j]=topmap[temp][j];//更新begin这一行
for(i=1;i<lsn[temp].index;i++){
lsn[j].path[i]=lsn[temp].path[i];//后面节点使用前面节点的路径
}
//lsn[j].path[i]=(char)(j+65);
lsn[j].index=lsn[temp].index;
}
}
}
}
printf("\n开始节点:%c\t结束节点:%c\n\n",(char)(beginNode),(char)(endNode));
printf("链路状态路由算法得出最短路径:\n");
if(topmap[beginNode-65][endNode-65]==10000) printf("%c-->%c没有最短路径",(char)(beginNode),(char)(endNode));
else if(topmap[endNode-65][beginNode-65]>0 && topmap[endNode-65][beginNode-65]<r) printf("%c-->%c",(char)(beginNode),(char)(endNode));
else {
for(j=0;j<lsn[endNode-65].index;j++){
if(j==0)printf("%c",lsn[endNode-65].path[j]);
else printf("-->%c",lsn[endNode-65].path[j]);
}
}
printf("\n\n");
return 0;
}