文字描述
十字链表是有向图的另一种链式存储结构. 在十字链表中,对应于有向图中每一条弧有一个结点,对应于每个顶点也有一个结点.这些结点的结构如下所示:
在弧结点中有5个域: 尾域tailvex和头域headvex分别指示弧尾和弧头这两个顶点在图中的位置,链域hlink指向与弧头相同的下一条弧, 而链域tlink指向弧尾相同的下一条弧, info域指向该弧的相关信息; 弧头相同的弧在同一链表上, 弧尾相同的弧也在同一链表上. 它们的头结点即为顶点结点,它由3个域组成:其中data域存储和顶点相关的信息,如顶点名称等; firstin和firstout为两个链域,分别指向以该顶点为弧头或弧尾的第一个弧结点.
示意图
算法分析
建立十字链表的时间复杂度和建立邻接表是相同的. 而且在十字链表中既容易找到以vi为尾的弧,也容易找到以vi为头的弧,因而容易求得顶点的出度和入度.
代码实现
1 /* 2 以十字链表作为图的存储结构创建图。 3 */ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #define MAX_VERTEX_NUM 20 //最大顶点数 9 #define DEBUG 10 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网} 11 typedef char InfoType; 12 typedef char VertexType; 13 //弧结点 14 typedef struct ArcBox{ 15 int tailvex, headvex;//该弧的尾和头顶点的位置 16 struct ArcBox *hlink, *tlink;//分别为弧头相同和弧尾相同的弧的链域 17 InfoType *info;//该弧相关的信息 18 }ArcBox; 19 //顶点结点 20 typedef struct VexNode{ 21 VertexType data;//顶点名称 22 ArcBox *firstin, *firstout;//分别指向该顶点第一条入弧和出弧 23 }VexNode; 24 typedef struct{ 25 VexNode xlist[MAX_VERTEX_NUM];//表头向量 26 int vexnum, arcnum;//有向图的当前顶点数和弧数 27 GraphKind kind;//图类型 28 }OLGraph; 29 30 /* 31 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。 32 */ 33 int LocateVex(OLGraph G, VertexType v) 34 { 35 int i = 0; 36 for(i=0; i<G.vexnum; i++){ 37 if(G.xlist[i].data == v) 38 return i; 39 } 40 return -1; 41 } 42 43 /* 44 若G中存在顶点位置loc存在,则返回其顶点名称 45 */ 46 VertexType LocateVInfo(OLGraph G, int loc) 47 { 48 return G.xlist[loc].data; 49 } 50 51 /* 52 采用十字链表的存储结构,构造有向图 53 */ 54 int CreateDG(OLGraph *G) 55 { 56 int i = 0, j = 0, k = 0, IncInfo = 0; 57 int v1 = 0, v2 = 0; 58 char tmp[10] = {0}; 59 ArcBox *p = NULL; 60 61 printf("输入顶点数,弧数,其他信息标志位: "); 62 scanf("%d,%d,%d", &G->vexnum, &G->arcnum, &IncInfo); 63 64 for(i=0; i<G->vexnum; i++){ 65 //输入顶点值 66 printf("输入第%d个顶点: ", i+1); 67 memset(tmp, 0, sizeof(tmp)); 68 scanf("%s", tmp); 69 //初始化指针 70 G->xlist[i].data = tmp[0]; 71 G->xlist[i].firstin = NULL; 72 G->xlist[i].firstout = NULL; 73 } 74 75 //输入各弧并构造十字链表 76 for(k=0; k<G->arcnum; k++){ 77 printf("输入第%d条弧(顶点1, 顶点2): ", k+1); 78 memset(tmp, 0, sizeof(tmp)); 79 scanf("%s", tmp); 80 sscanf(tmp, "%c,%c", &v1, &v2); 81 //确定顶点v1和v2在图中的位置 82 i = LocateVex(*G, v1); 83 j = LocateVex(*G, v2); 84 //对弧结点赋值 85 p = (ArcBox *) malloc(sizeof(ArcBox)); 86 p->tailvex = i; 87 p->headvex = j; 88 p->hlink = G->xlist[j].firstin; 89 p->tlink = G->xlist[i].firstout; 90 p->info = NULL; 91 //完成在入弧和出弧链头的插入 92 G->xlist[j].firstin = p; 93 G->xlist[i].firstout = p; 94 //若弧有相关的信息,则输入 95 if(IncInfo){ 96 //Input(p->info); 97 } 98 } 99 return 0; 100 } 101 102 /* 103 采用十字链表的存储结构,构造图 104 */ 105 int CreateGraph(OLGraph *G) 106 { 107 printf("输入图类型: +有向图(0), -有向网(1), -无向图(2), -无向网(3): "); 108 scanf("%d", &G->kind); 109 switch(G->kind){ 110 case DG: 111 return CreateDG(G); 112 case DN: 113 case UDN: 114 case UDG: 115 default: 116 printf("还不支持! "); 117 return -1; 118 } 119 } 120 121 /* 122 输出图的信息 123 */ 124 void printG(OLGraph G) 125 { 126 if(G.kind == DG){ 127 printf("类型:有向图;顶点数 %d, 弧数 %d ", G.vexnum, G.arcnum); 128 }else if(G.kind == DN){ 129 printf("类型:有向网;顶点数 %d, 弧数 %d ", G.vexnum, G.arcnum); 130 }else if(G.kind == UDG){ 131 printf("类型:无向图;顶点数 %d, 弧数 %d ", G.vexnum, G.arcnum); 132 }else if(G.kind == UDN){ 133 printf("类型:无向网;顶点数 %d, 弧数 %d ", G.vexnum, G.arcnum); 134 } 135 136 int i = 0; 137 ArcBox *fi = NULL; 138 ArcBox *fo = NULL; 139 for(i=0; i<G.vexnum; i++){ 140 printf("%c: ", G.xlist[i].data); 141 fi = G.xlist[i].firstin; 142 fo = G.xlist[i].firstout; 143 printf("(hlink="); 144 while(fi){ 145 #ifdef DEBUG 146 printf("%c->%c; ", LocateVInfo(G, fi->tailvex), LocateVInfo(G, fi->headvex)); 147 #else 148 printf("%d->%d; ", fi->tailvex, fi->headvex); 149 #endif 150 fi = fi->hlink; 151 } 152 printf(") (tlink="); 153 while(fo){ 154 #ifdef DEBUG 155 printf("%c->%c; ", LocateVInfo(G, fo->tailvex), LocateVInfo(G, fo->headvex)); 156 #else 157 printf("%d->%d; ", fo->tailvex, fo->headvex); 158 #endif 159 fo = fo->tlink; 160 } 161 printf(") "); 162 } 163 return; 164 } 165 166 int main(int argc, char *argv[]) 167 { 168 OLGraph G; 169 if(CreateGraph(&G) > -1){ 170 printG(G); 171 } 172 return 0; 173 }
代码运行