码迷,mamicode.com
首页 > 其他好文 > 详细

看数据结构写代码(36) 图的邻接表表示与实现

时间:2015-04-09 11:56:46      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:图的邻接表表示法   图的邻接表实现   数据结构   

图的邻接表表示法,是为每一个顶点建立一个链表,链表里存放着相同弧尾的 弧的信息,这些链表顺序存放在数组中。下面是无向图g2的邻接表 

技术分享技术分享

邻接表 比 邻接矩阵 节省空间,同时 也带来一些操作上的 不便,例如 看 两个顶点是否 相邻,需要 遍历 链表,在 求 无向图顶点的度时,只需 遍历 顶点的链表,而 求 有向图 顶点的度 需要 遍历 整个图 查找 弧头 为这个顶点的 个数。 如果 不想这样做,可以 建立 逆邻接表,即 链表里 存放着 相同 弧头的 弧 的信息。 下一节 要说的 十字链表 类似于这种结构。

下面 上代码:

// Graph.cpp : 定义控制台应用程序的入口点。
//图的邻接表 表示法

#include "stdafx.h"
#include <cstdlib>
#include <climits>
#define MAX_VERTEX_NUM 20
#define INFINITY INT_MAX
enum E_Graph_Kind  
{  
    DG = 0,//有向图  
    DN,//有向网  
    UDG,//无向图  
    UDN,//无向网  
};  
struct ArcNode//边(弧)
{
	int adjVex;//顶点在数组中的位置
	ArcNode * nextAdj;
	int weight;//权值
};

typedef struct VNode//顶点
{
	ArcNode * head;//头指针
	char vexName;//顶点名称
}AdjList[MAX_VERTEX_NUM];
struct Graph//图
{
	AdjList list;//邻接表
	int arcNum,vexNum;
	E_Graph_Kind kind;
};

//顶点在数组中的位置
int vexLocation(Graph g,char vex){
	for (int i = 0; i < g.vexNum; i++){
		if (g.list[i].vexName == vex){
			return i;
		}
	}
	return -1;
}

ArcNode * getHeadNode(){//获得头节点..
	ArcNode * node = (ArcNode*)malloc(sizeof(ArcNode));
	if (node != NULL){
		node->adjVex = -1;
		node->nextAdj = NULL;
		node->weight = INFINITY;
	}
	return node;
}

ArcNode * getArcNode(Graph g,char vexName){
	ArcNode * node = getHeadNode();
	if (node != NULL){
		int location = vexLocation(g,vexName);
		node->adjVex = location;
	}
	return node;
}

void createDG(Graph * graph);  
void createDN(Graph * graph);  
void createUDG(Graph * graph);  
void createUDN(Graph * graph);  
  
void graphCreate(Graph * graph){  
    E_Graph_Kind kind;  
    printf("请输入要创建的图的类型(有向图:0,有向网:1,无向图:2,无向网:3)\n");  
    scanf("%d",&kind);  
    switch (kind){  
    case DG:  
        createDG(graph);  
        break;  
    case DN:  
        createDN(graph);  
        break;  
    case UDG:  
        createUDG(graph);  
        break;  
    case UDN:  
        createUDN(graph);  
        break;  
    default:  
        break;  
    }  
} 

//有向图
void createDG(Graph * g){
	g->kind = DG;
	printf("输入图的顶点树 和 边(弧)树\n");
	scanf("%d%d%*c",&g->vexNum,&g->arcNum);  
    //构造顶点集  
    printf("请输入顶点集\n");  
    for (int i = 0; i < g->vexNum; i++){  
        char name;
		scanf("%c",&name);
		g->list[i].vexName = name;
		g->list[i].head = getHeadNode();//头指针指向头节点.
    }  
    //构造顶点关系  
    fflush(stdin);  
    printf("请输入顶点的关系\n");  
    for (int i = 0; i < g->arcNum; i++){  
        char vex1,vex2;  
        scanf("%c%c%*c",&vex1,&vex2);  
		int location1 = vexLocation(*g,vex1);    
		ArcNode * node = getArcNode(*g,vex2);
		node->nextAdj = g->list[location1].head->nextAdj;
		g->list[location1].head->nextAdj = node;
    }  
}
//有向网..
void createDN(Graph * g){
	g->kind = DN;
	printf("输入图的顶点树 和 边(弧)树\n");
	scanf("%d%d%*c",&g->vexNum,&g->arcNum);  
    //构造顶点集  
    printf("请输入顶点集\n");  
    for (int i = 0; i < g->vexNum; i++){  
        char name;
		scanf("%c",&name);
		g->list[i].vexName = name;
		g->list[i].head = getHeadNode();
    }  
    //构造顶点关系  
    fflush(stdin);  
    printf("请输入顶点的关系\n");  
    for (int i = 0; i < g->arcNum; i++){  
        char vex1,vex2;
		int weight;
		scanf("%c%c%d%*c",&vex1,&vex2,&weight);  
		int location1 = vexLocation(*g,vex1);
		ArcNode * node = getArcNode(*g,vex2);
		node->weight = weight;
		node->nextAdj = g->list[location1].head->nextAdj;
		g->list[location1].head->nextAdj = node;
    }  
}
//无向图
void createUDG(Graph * g){
	g->kind = UDG;
	printf("输入图的顶点树 和 边(弧)树\n");
	scanf("%d%d%*c",&g->vexNum,&g->arcNum);  
    //构造顶点集  
    printf("请输入顶点集\n");  
    for (int i = 0; i < g->vexNum; i++){  
        char name;
		scanf("%c",&name);
		g->list[i].vexName = name;
		g->list[i].head = getHeadNode();
    }  
    //构造顶点关系  
    fflush(stdin);  
    printf("请输入顶点的关系\n");  
    for (int i = 0; i < g->arcNum; i++){  
        char vex1,vex2;
		scanf("%c%c%*c",&vex1,&vex2);  
		int location1 = vexLocation(*g,vex1);
		ArcNode * node1 = getArcNode(*g,vex2);
		node1->nextAdj = g->list[location1].head->nextAdj;
		g->list[location1].head->nextAdj = node1;
		int location2 = vexLocation(*g,vex2);
		ArcNode * node2 = getArcNode(*g,vex1);
		node2->nextAdj = g->list[location2].head->nextAdj;
		g->list[location2].head->nextAdj = node2;
    }  
}
//无向网
void createUDN(Graph * g){
	g->kind = UDN;
	printf("输入图的顶点树 和 边(弧)树\n");
	scanf("%d%d%*c",&g->vexNum,&g->arcNum);  
    //构造顶点集  
    printf("请输入顶点集\n");  
    for (int i = 0; i < g->vexNum; i++){  
        char name;
		scanf("%c",&name);
		g->list[i].vexName = name;
		g->list[i].head = getHeadNode();
    }  
    //构造顶点关系  
    fflush(stdin);  
    printf("请输入顶点的关系\n");  
    for (int i = 0; i < g->arcNum; i++){  
        char vex1,vex2;
		int weight;
		scanf("%c%c%d%*c",&vex1,&vex2,&weight);  
		int location1 = vexLocation(*g,vex1);
		ArcNode * node1 = getArcNode(*g,vex2);
		node1->weight = weight;
		node1->nextAdj = g->list[location1].head->nextAdj;
		g->list[location1].head->nextAdj = node1;
		int location2 = vexLocation(*g,vex2);
		ArcNode * node2 = getArcNode(*g,vex1);
		node2->weight = weight;
		node2->nextAdj = g->list[location2].head->nextAdj;
		g->list[location2].head->nextAdj = node2;
    }  
}

void graphDestory(Graph * g){
	for (int i = 0; i < g->vexNum; i++){
		ArcNode * next = g->list[i].head;
		while (next != NULL){
			ArcNode * freeNode = next;
			next = next->nextAdj;
			free(freeNode);
		}
		g->list[i].head = NULL;
		g->list[i].vexName = ' ';
	}
	g->vexNum = g->arcNum = 0;
}
//vex1 和 vex2是否相邻..
bool grphIsAdj(Graph g,char vex1,char vex2){
	int location = vexLocation(g,vex1);
	ArcNode * next = g.list[location].head->nextAdj;//第一个节点是头结点的后继
	while (next != NULL){
		if (g.list[next->adjVex].vexName == vex2){
			return true;
		}
		next = next->nextAdj;
	}
	return false;
}
//顶点vex的度.
//有向 = 出度 + 入度
//无向 = 出度
int graphDegree(Graph g,char vex){
	int degree = 0;
	int location = vexLocation(g,vex);
	ArcNode * next = g.list[location].head->nextAdj;
	while (next != NULL){//出度
		degree ++;
		next = next->nextAdj;
	}
	if (g.kind == DG || g.kind == DN){
		//有向图还需要遍历图,寻找入度.
		for (int i = 0; i < g.vexNum; i++){
			ArcNode * next = g.list[i].head->nextAdj;
			while (next != NULL){
				if (next->adjVex == location){
					degree ++;
				}
				next = next->nextAdj;
			}
		}
	}
	return degree;
}
//vex 的第一个邻接点
char firstAdj(Graph g,char vex){
	int location = vexLocation(g,vex);
	ArcNode * next = g.list[location].head->nextAdj;
	if (next != NULL){
		return g.list[next->adjVex].vexName;
	}
	return ' ';
}
//vex1 相对于 vex2 的下一个邻接点。。。
char nextAdj(Graph g,char vex1,char vex2){
	int location = vexLocation(g,vex1);
	ArcNode * next = g.list[location].head->nextAdj;
	while (next != NULL){//查找到 vex2
		if (g.list[next->adjVex].vexName == vex2){
			break;
		}
		next = next->nextAdj;
	}
	if (next != NULL){
		ArcNode * nextNode = next->nextAdj;
		if (nextNode != NULL){
			return g.list[nextNode->adjVex].vexName;
		}
	}
	return ' ';
}
//插入顶点
void insertVex(Graph * g,char vex){
	if (g->vexNum < MAX_VERTEX_NUM){
		g->list[g->vexNum].vexName = vex;
		g->list[g->vexNum].head = getHeadNode();
		g->vexNum++;
	}
}
//删除顶点
void deleteVex(Graph * g,char vex){
	int location = vexLocation(*g,vex);
	//释放空间
	ArcNode * next = g->list[location].head->nextAdj;
	int delNum = 0;
	while (next != NULL){
		ArcNode * freeNode = next;
		next = next->nextAdj;
		free(freeNode);
		delNum++;
	}
	//vex下面的 顶点上移
	for (int i = location + 1; i < g->vexNum; i++){
		g->list[i-1] = g->list[i];
	}
	g->vexNum --;
	//删除与顶点vex 相关的边(弧)(以及更新 所有节点的 adjVex )要遍历图..
	for (int i = 0; i < g->vexNum; i++){
		ArcNode * next = g->list[i].head->nextAdj;
		ArcNode * pre = g->list[i].head;
		while (next != NULL){
			if (next->adjVex == location){
				ArcNode * freeNode = next;
				next = next->nextAdj;
				pre->nextAdj = next;
				free(freeNode);
				delNum++;
			}
			else {
				if (next->adjVex > location){//在顶点下面的节点位置要减1
					next->adjVex --;
				}
				pre = next;
				next = next->nextAdj;
			}
		}
	}
	g->arcNum -= delNum;//有向
	if (g->kind == UDG || g->kind == UDN){
		g->arcNum += delNum/2;
	}
}
//插入边(弧)
void insertArc(Graph * g,char vex1,char vex2){
	int location1 = vexLocation(*g,vex1);
	ArcNode * node1 = getArcNode(*g,vex2);
	node1->nextAdj = g->list[location1].head->nextAdj;
	g->list[location1].head->nextAdj = node1;
	//无向图需要插入另外一边.
	if (g->kind == UDG || g->kind == UDN){
		int location2 = vexLocation(*g,vex2);
		ArcNode * node2 = getArcNode(*g,vex1);
		node2->nextAdj = g->list[location2].head->nextAdj;
		g->list[location2].head->nextAdj = node2;
	}
	g->arcNum ++;
}
//删除边(弧)
void deleteArc(Graph * g,char vex1,char vex2){
	g->arcNum--;
	int location1 = vexLocation(*g,vex1);
	int location2 = vexLocation(*g,vex2);
	ArcNode * next = g->list[location1].head->nextAdj;
	ArcNode * pre = g->list[location1].head;
	while (next != NULL){
		if (next->adjVex == location2){
			pre->nextAdj = next->nextAdj;
			free(next);
			break;
		}
		pre = next;
		next = next->nextAdj;
	}
	if (g->kind == UDG || g->kind == UDN ){//无向图还需要删除 另外一边
		next = g->list[location2].head->nextAdj;
		pre = g->list[location2].head;
		while (next != NULL){
			if (next->adjVex == location1){
				pre->nextAdj = next->nextAdj;
				free(next);
				break;
			}
			pre = next;
			next = next->nextAdj;
		}
	}
}

void printGrahp(Graph g){
	for (int i = 0; i < g.vexNum; i++){
		printf("%c的邻接点有:",g.list[i].vexName);
		ArcNode * next = g.list[i].head->nextAdj;
		while (next != NULL){
			printf("%c",g.list[next->adjVex].vexName);
			next = next->nextAdj;
		}
		printf("\n");
	}
}


int _tmain(int argc, _TCHAR* argv[])
{
	Graph g;
	graphCreate(&g);
	printGrahp(g);
	printf("图的顶点数:%d,边(弧)树为:%d\n",g.vexNum,g.arcNum);
	char first = firstAdj(g,'a');
	char next = nextAdj(g,'a','c');
	char * isAdj = grphIsAdj(g,'c','d')? "相邻" : "不相邻";
	int degree = graphDegree(g,'d');
	printf("a的第一个邻接点是%c,a的c邻接点的下一个邻接点是:%c\n",first,next);
	printf("c 和 d %s,d的度为:%d\n",isAdj,degree);
	insertVex(&g,'e');
	printf("插入e顶点之后图结构如下:\n");
	printGrahp(g);
	insertArc(&g,'a','e');
	printf("插入(a,e)边(弧)之后图结构如下:\n");
	printGrahp(g);
	deleteArc(&g,'d','c');
	printf("删除(d,c)边(弧)之后图结构如下:\n");
	printGrahp(g);
	deleteVex(&g,'a');
	printf("删除顶点a之后图结构如下:\n");
	printGrahp(g);
	printf("图的顶点数:%d,边(弧)树为:%d\n",g.vexNum,g.arcNum);
	//及时销毁内存是个好习惯
	graphDestory(&g);
	return 0;
}
运行截图:

技术分享

最后 图的 顶点树为 4, 边(弧) 数 为 1

看数据结构写代码(36) 图的邻接表表示与实现

标签:图的邻接表表示法   图的邻接表实现   数据结构   

原文地址:http://blog.csdn.net/fuming0210sc/article/details/44957133

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!