图的十字链表存储结构

图的存储不外乎一个记录图中顶点的数组,一个表示弧的结构.十字链表的表示如下:

typedef char Graph_style;
typedef struct Graph_node{  //弧结点
	int itail;   //该弧的尾顶点所在顶点数组中的位置
	struct Graph_node *itail_point;   //指向下一个以itail为尾的弧
	int ihead;	//该弧的头顶点所在顶点数组中的位置
	struct Graph_node *ihead_point;		//指向下一个以Ihead为头的弧
}Graph_node;
typedef struct Graph_head{  存储图中顶点的数据结构                            
	Graph_node *in_point;  //指向一个新的以该顶点为尾的弧..
	Graph_style data;
	Graph_node *out_point;	//指向一个新的以该顶点为头的弧..
}Graph_head;
//图的结构...
typedef struct Graph{
	int Graph_vertexcount;//图的顶点个数
   	int Graph_arccount;   //图的弧条数
	Graph_head *array_head;//指向存放的所有顶点,以及顶点中的数据结构
 	Graph_style *local_array;  //专门存放顶点的内部数组...其中只有顶点.与 array_head中的顶点序列相同  专门用来确定弧头弧尾的位置                   
}Graph;


在对图进行操作的时候,还需要一个确定弧尾和弧头在array_head中的位置函数...

int Local_Int(Graph &G, Graph_style head_date){ //寻找该顶点在 图G头结点数组中的位置
	int count = 0;
	while(count < G.Graph_vertexcount){
		if(G.local_array[count] == head_date)
			return count;
		count++;
	}
	printf("未找到该顶点!\n");
}


十字链表中的核心代码.

	fscanf(fp, "%c%*c%*c%*c%c%*c", &tail, &head);
		itail = Local_Int(G, tail);
		jhead = Local_Int(G, head);
		arc_point = (Graph_node *) malloc(sizeof(Graph_node));
		arc_point->itail = itail;	//弧尾在头顶点数组中的位置
		arc_point->ihead = jhead;	//弧头的位置
		arc_point->itail_point = G.array_head[itail].out_point;  //倒叙插入法..与新弧的尾顶点相同的后继..始终是放在该弧的尾顶点的out指针域中的...
		arc_point->ihead_point = G.array_head[jhead].in_point;	 //倒叙插入法..与新弧的头顶点相同的后继..始终是放在该弧的头顶点的in指针域中的...
		//给头顶点的指针域赋值
		G.array_head[itail].out_point = arc_point;	//arc_point这条弧是从itail-->jhead的..所以它是从itail出去的..
		G.array_head[jhead].in_point  = arc_point;	//进入到jhead所在的顶点..
			//在以后的倒插过程中..新弧的各个方向的后继..只需在其各个顶点中的指针域中寻找即可完成..无需刻意的到弧中去需找

从代码上分析原理...首先读取一条弧 tail-->head ,然后对这条弧的弧尾和弧头的位置进行查询.具体是itail = Local_Int(G, tail);          jhead = Local_Int(G, head);

然后对该弧分配一块内存...从对弧的数据结构定义上我们知道:

typedef struct Graph_node{  //弧结点
	int itail;   //该弧的尾顶点所在顶点数组中的位置
	struct Graph_node *itail_point;   //指向下一个以itail为尾的弧
	int ihead;	//该弧的头顶点所在顶点数组中的位置
	struct Graph_node *ihead_point;		//指向下一个以Ihead为头的弧
}Graph_node;

它的 itail和ihead分别表示该弧在图G顶点数组array_head中的位置...itail_point 和 ihead_point 指针分别指向 与这条弧的弧尾相同的弧 和 与这条弧的弧头相同的弧..即将图中相同尾顶点的弧 itail--> X  链接起来....和 将头顶点相同的弧X-->ihead  链 接起来..

顶点的数据结构中:

typedef struct Graph_head{  存储图中顶点的数据结构                            
	Graph_node *in_point;  //指向一个新的以该顶点为尾的弧..
	Graph_style data;
	Graph_node *out_point;	//指向一个新的以该顶点为头的弧..
}Graph_head;

in_point 和out_point  分别指向 进入到data的(以data为头的弧) 和 从data出去的(以data为尾的弧)...

由于在对弧进行操作的时候采用的 倒叙将弧逐步 链接成链表的...所以需要一个变量来保存上一个关系弧的位置信息. .这里我们用头结点中的in_point 和 out_point 来表示..

在对头顶点的指针进行赋值的时候先初始化为NULL , 使得在第一次执行到:

arc_point->itail_point = G.array_head[itail].out_point; 

 arc_point->ihead_point = G.array_head[jhead].in_point; 

这两条语句的时候 ..将该弧作为最后一条弧..并将指针域 赋为NULL..来表示结束...

而头结点中的指针信息 ..始终是指向刚刚那条弧的  G.array_head[itail].out_point = arc_point;     G.array_head[jhead].in_point  = arc_point;

由于是头顶点中的指针是在对弧之后操作的..所以..头顶点中就可以保存 上一个弧的信息了. ..

对于一条弧...tail-->head; 都有..这条弧是从tail发出的..即以tail为尾..从head进入...即以head 为头...所以在相应的头顶点数据机构中肯定可以赋值..而这个指针值.将恰好是 将来与此弧 tail 相同..或者 head相同 的弧信息...新弧只需要利用在头顶点中保持的信息 即可完成 相应链表的建立...

 

=================================================================

 

 

===============================================================

十字链表 完整代码. .

===============================================================

/************************************************************************/
/*                    图的十字链表存储                                   */
/************************************************************************/
typedef char Graph_style;
typedef struct Graph_node{  //弧结点
	int itail;   //该弧的尾顶点所在顶点数组中的位置
	struct Graph_node *itail_point;   //指向下一个以itail为尾的弧
	int ihead;	//该弧的头顶点所在顶点数组中的位置
	struct Graph_node *ihead_point;		//指向下一个以Ihead为头的弧
}Graph_node;
typedef struct Graph_head{
	Graph_node *in_point;  //指向一个新的以该顶点为尾的弧..
	Graph_style data;
	Graph_node *out_point;	//指向一个新的以该顶点为头的弧..
}Graph_head;
typedef struct Graph{
	int Graph_vertexcount;
	int Graph_arccount;
	Graph_head *array_head;
	Graph_style *local_array;
}Graph;

int Local_Int(Graph &G, Graph_style head_date){ //寻找该顶点在 图G头结点数组中的位置
	int count = 0;
	while(count < G.Graph_vertexcount){
		if(G.local_array[count] == head_date)
			return count;
		count++;
	}
	printf("未找到该顶点!\n");
}

void Creat_Graph_Link_2(Graph &G){
	int ver, arc;
	Graph_style tail, head;
	int itail, jhead;
	FILE *fp = fopen("C://Users//Administrator//Desktop//图//图的十字链表.txt", "r");
	fscanf(fp, "%d %d%*c", &G.Graph_vertexcount, &G.Graph_arccount);
	fscanf(fp, "%*s%*c");
	G.local_array = (Graph_style *)malloc(G.Graph_vertexcount * sizeof(Graph_style));
	fscanf(fp, "%s%*c", G.local_array);
	fscanf(fp, "%*s%*c");
//	printf("G.Graph_vertexcount = %d, G.Graph_arccount = %d,G.local_array = %s", G.Graph_vertexcount, G.Graph_arccount, G.local_array);
	G.array_head = (Graph_head *) malloc(G.Graph_vertexcount * sizeof(Graph_head));
	for(ver = 0; ver < G.Graph_vertexcount; ver++){		//头顶点 初始化...
		G.array_head[ver].data = G.local_array[ver];
		G.array_head[ver].in_point = NULL;
		G.array_head[ver].out_point = NULL;
	}
	
	for(arc = 0; arc < G.Graph_arccount; arc++){
		Graph_node *arc_point = NULL; //弧结点
		fscanf(fp, "%c%*c%*c%*c%c%*c", &tail, &head);
		itail = Local_Int(G, tail);
		jhead = Local_Int(G, head);
		arc_point = (Graph_node *) malloc(sizeof(Graph_node));
		arc_point->itail = itail;	//弧尾在头顶点数组中的位置
		arc_point->ihead = jhead;	//弧头的位置
		arc_point->itail_point = G.array_head[itail].out_point;  //倒叙插入法..与新弧的尾顶点相同的后继..始终是放在该弧的尾顶点的out指针域中的...
		arc_point->ihead_point = G.array_head[jhead].in_point;	 //倒叙插入法..与新弧的头顶点相同的后继..始终是放在该弧的头顶点的in指针域中的...
		//给头顶点的指针域赋值
		G.array_head[itail].out_point = arc_point;	//arc_point这条弧是从itail-->jhead的..所以它是从itail出去的..
		G.array_head[jhead].in_point  = arc_point;	//									 进入到jhead所在的顶点..
											//在以后的倒插过程中..新弧的各个方向的后继..只需在其各个顶点中的指针域中寻找即可完成..无需刻意的到弧中去需找
	}
	fclose(fp);
}

void Show_Graph(Graph &G){   //打印顶点的各个方向的弧.
	int ver, arc;
	Graph_node *p;
	for(ver = 0; ver < G.Graph_vertexcount; ver++){
		p   = G.array_head[ver].out_point;	//先打印以顶点为尾的弧..
		printf("以%c为尾的弧: \n", G.array_head[ver].data);
		while(p){
			
			printf("%c-->%c\n", G.array_head[p->itail].data, G.array_head[p->ihead].data);
			p = p->itail_point;	 //让p指向下一条以 该弧的尾顶点相同的弧...
		}
		p	= G.array_head[ver].in_point;
		printf("以%c为头的弧: \n", G.array_head[ver].data);
		while(p){
			
			printf("%c-->%c\n", G.array_head[p->itail].data, G.array_head[p->ihead].data);
			p = p->ihead_point;
		}
	}

}

int main(){
	Graph G;
	Creat_Graph_Link_2(G);
	Show_Graph(G);

	return 0;
}


============================================================================================================================

我擦.. 手好生啊 .. 不知所云 啊.. . ...万事开头难啊. . .就这么凑合下吧 .. .

2013年11月27日17:17:06

 

 

 


 



 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值