十字链表是将邻接表和逆邻接表结合在一起的一种有向图的数据结构
十字链表的节点结构体表示的是一个节点到另一个节点的边,并且此由指出节点(from)和指入节点(to)共同使用,因此大大节省了内存。
先直观感受一下十字链表的存储方式,观察一下规律
接下来看一下我定义的边节点的结构体,两个数据域表示from到to的边,两个指针域其实可以看做将该节点挂去何处,in_pointer就是将该节点挂在to顶点的入度链表中,out_pointer就是将该节点挂在from顶点的出度链表中
这是我定义的十字链表结构体,其中包含该图的顶点数与边数,并且包含了顶点结构体head,其中包含了顶点的元素信息,和入度与出度指针变量
其实原理很简单,就是有一条from到to的边节点,现在把这个边节点先插入到from的出度链表下再插到to的入度链表下。
下面随便用个有向图举下例子:
找个DA边(由D指出到A),先将该边节点插到D(from)的出度链表中,第一步先在D顶点中判断其出度链表是否为空,若为空,直接将此节点插入D顶点的出度指针变量中(map->head[from].out_pointer)
若不为空则用to与D下出度链表中已挂载的节点的to比较大小,判断是进入下一个节点还是插在此节点之前。第二步再将该边节点插入到A(to)的入度链表中,过程同上。
总的来说十字链表并不算复杂,各位可以先一下我用C语言实现的代码
#include<stdio.h>
//十字链表(有向图的存储方式)
//节点结构体中有两个指针,一个连接出度,一个连接入度
#define MAX 20
//from到to的边要插到from的出度链表中,to的入度链表中
struct Node
{
int from, to;
struct Node* in_pointer;
struct Node* out_pointer;
};
struct Cross_List//一个图的结构体中应包含图的顶点数和边数
{
int vex, edge;
struct
{
char head_ele;
struct Node* in_pointer;
struct Node* out_pointer;
}head[MAX];
};
void creat(struct Cross_List* map);
void show(struct Cross_List* map);
void insert(struct Cross_List* map, char from, char to);
void creat(struct Cross_List* map)
{
char from, to;
printf("要创建几个节点,几条边:");
scanf("%d%d", &map->vex, &map->edge);
getchar();
for (int i = 0; i < map->vex; i++)//初始化图的节点
{
map->head[i].head_ele = i + 'A';
map->head[i].in_pointer = NULL;
map->head[i].out_pointer = NULL;
}
printf("请输入图的边:\n");
for (int i = 0; i < map->edge; i++)//建立十字链表
{
scanf("%c%c", &from, &to);
getchar();
insert(map, from, to);
}
}
void insert(struct Cross_List* map,char from,char to)
{
struct Node* p = malloc(sizeof(struct Node));
struct Node* now;
struct Node* before;
struct Node* q;
p->from = from - 'A';
p->to = to - 'A';
p->in_pointer = NULL;
p->out_pointer = NULL;
//--------------------------插入出度
now = map->head[from - 'A'].out_pointer;
if (now && now->to < to - 'A')//判断链表不为空,并且第一个元素小于要插入的元素
{
while (now)
{
if (to - 'A' > now->to)
{
before = now;
now = now->out_pointer;
}
else
break;
}
p->out_pointer = now;
before->out_pointer = p;
}
else
{
q = map->head[from - 'A'].out_pointer;
map->head[from - 'A'].out_pointer = p;
p->out_pointer = q;
}
//-------------------------------插入入度
now = map->head[to - 'A'].in_pointer;
if (now && now->from < from - 'A')
{
while (now)
{
if (from - 'A' > now->from)
{
before = now;
now = now->in_pointer;
}
else
break;
}
p->in_pointer = now;
before->in_pointer = p;
}
else
{
q = map->head[to - 'A'].in_pointer;
map->head[to - 'A'].in_pointer = p;
p->in_pointer = q;
}
}
void show(struct Cross_List* map)
{
struct Node* p;
for (int i = 0; i < map->vex; i++)
{
printf("与%c连接的出度节点有:",map->head[i].head_ele);
p = map->head[i].out_pointer;
while (p)
{
printf("%c ", p->to+'A');
p = p->out_pointer;
}
printf("\n");
printf("与%c连接的入度节点有:", map->head[i].head_ele);
p = map->head[i].in_pointer;
while (p)
{
printf("%c ", p->from+'A');
p = p->in_pointer;
}
printf("\n");
}
}
int main()
{
struct Cross_List map;
creat(&map);
show(&map);
return 0;
}
接下来看两个我在vs2019下运行的结果
十字链表分享结束,有问题的朋友可以在下方留言(发现bug的话,提醒告诉博主哦^ _ ^)