? 树具有灵活性,并且存在许多不同的树的应用,但是就树本身而言有一定的局限性,树只能表示层次关系,比如父子关系。而其他的比如兄弟关系只能够间接表示。
推广---? 图
图形结构中,数据元素之间的关系是任意的。
无向图:n个顶点找两条,没有方向,
对称矩阵:
一个对称矩阵是指矩阵的主对角线两侧的元素相等。在这个矩阵中,通过观察可以发现对称性质:矩阵的第i行第j列的元素等于第j行第i列的元素。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
int n, m; //n个顶点,m条边
VexType vex[N];//一维数组存放所有顶点的数据信息
EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
//1.建图
adjGraph g = createGraph();
//2.输出图的信息
print(g);
printDegree(g);
return 0;
}
adjGraph createGraph()//建图
{
adjGraph g;
memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
// g.edge 邻接矩阵
//sizeof(g.edge) 数组占用的总字节数
scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
getchar();//吸收换行符
//1.输入n个顶点
for (int i = 0; i < g.n; i++) {
scanf("%c ", &g.vex[i]);
}
//2.输入m条边,按照邻接矩阵存图
for (int i = 0; i < g.m; i++) {
char v1, v2;
scanf("\n%c %c", &v1, &v2);//读入当前边的2个顶点
int n1 = v1 - 'A', n2 = v2 - 'A';
//将顶点字符转换为对应的数组索引。
// 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
// 可以得到对应的数组索引(0、1、2等)。
g.edge[n1][n2] = g.edge[n2][n1] = 1;
//无向图,邻接矩阵对应的n1行n2列和n2n1列都赋值为1(邻接矩阵的对称性)
//将对应的邻接矩阵元素设置为1,表示图中对应的顶点之间存在一条边。
}
return g;
}
void print(adjGraph g)
{
printf("图有%d个顶点,%d条边\n", g.n, g.m);
printf("图的顶点是:");
for (int i = 0; i < g.n; i++) {
printf("%c ", g.vex[i]);
}
printf("\n图的邻接矩阵是:\n");
for (int i = 0; i < g.n; i++) {
for (int j = 0; j < g.n; j++) {
printf("%4d", g.edge[i][j]);
}
printf("\n");
}
}
void printDegree(adjGraph g)
{
printf("图中每个顶点的度数是:");
for (int i = 0; i < g.n; i++) {
int degree = 0;
for (int j = 0; j < g.n; j++) {
if (g.edge[i][j] == 1) {
degree++;
}
}
printf("%c: %d ", g.vex[i], degree);
}
printf("\n");
}
输入样例:
修改的部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
int n, m; //n个顶点,m条边
VexType vex[N];//一维数组存放所有顶点的数据信息
EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
//1.建图
adjGraph g = createGraph();
//2.输出图的信息
print(g);
printDegree(g);
return 0;
}
adjGraph createGraph()//建图
{
adjGraph g;
memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
// g.edge 邻接矩阵
//sizeof(g.edge) 数组占用的总字节数
scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
getchar();//吸收换行符
//1.输入n个顶点
for (int i = 0; i < g.n; i++) {
scanf("%c ", &g.vex[i]);
}
//2.输入m条边,按照邻接矩阵存图
for (int i = 0; i < g.m; i++) {
char v1, v2;
scanf("\n%c %c", &v1, &v2);//读入当前边的2个顶点
int n1 = v1 - 'A', n2 = v2 - 'A';
//将顶点字符转换为对应的数组索引。
// 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
// 可以得到对应的数组索引(0、1、2等)。
g.edge[n1][n2] = 1;
//有向图,邻接矩阵对应的n1行n2列赋值为1
//将对应的邻接矩阵元素设置为1,表示图中对应的顶点之间存在一条边。
}
return g;
}
void print(adjGraph g)
{
printf("图有%d个顶点,%d条边\n", g.n, g.m);
printf("图的顶点是:");
for (int i = 0; i < g.n; i++) {
printf("%c ", g.vex[i]);
}
printf("\n图的邻接矩阵是:\n");
for (int i = 0; i < g.n; i++) {
for (int j = 0; j < g.n; j++) {
printf("%4d", g.edge[i][j]);
}
printf("\n");
}
}
void printDegree(adjGraph g)
{
printf("图中每个顶点的入度是:\n");
for (int i = 0; i < g.n; i++) {
int indegree = 0;
for (int j = 0; j < g.n; j++) {
if (g.edge[j][i] == 1) {
indegree++;
}
}
printf("%c: %d \n", g.vex[i], indegree);
}
printf("图中每个顶点的出度是:\n");
for (int i = 0; i < g.n; i++) {
int outdegree = 0;
for (int j = 0; j < g.n; j++) {
if (g.edge[i][j] == 1) {
outdegree++;
}
}
printf("%c: %d \n", g.vex[i], outdegree);
}
}
测试样例:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
int n, m; //n个顶点,m条边
VexType vex[N];//一维数组存放所有顶点的数据信息
EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
//1.建图
adjGraph g = createGraph();
//2.输出图的信息
print(g);
printDegree(g);
return 0;
}
adjGraph createGraph()//建图
{
adjGraph g;
memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
// g.edge 邻接矩阵
//sizeof(g.edge) 数组占用的总字节数
scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
getchar();//吸收换行符
//1.输入n个顶点
for (int i = 0; i < g.n; i++) {
scanf("%c ", &g.vex[i]);
}
//2.输入m条边,按照邻接矩阵存图
// 将邻接矩阵初始化为INF
for (int i = 0; i < g.m; i++) {
for (int j = 0; j < g.m; j++) {
g.edge[i][j] = INF;
}
}
for (int i = 0; i < g.m; i++) {
char v1, v2;
int weight;
scanf("\n%c %d %c", &v1, &weight, &v2);//读入当前边的2个顶点
int n1 = v1 - 'A', n2 = v2 - 'A';
//将顶点字符转换为对应的数组索引。
// 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
// 可以得到对应的数组索引(0、1、2等)。
if (n1 == n2) {
g.edge[n1][n2] = 0;
}
else {
g.edge[n1][n2] = weight;
g.edge[n2][n1] = INF; // 反方向的边权值设置为INF
}
}
return g;
}
void print(adjGraph g)
{
printf("图有%d个顶点,%d条边\n", g.n, g.m);
printf("图的顶点是:");
for (int i = 0; i < g.n; i++) {
printf("%c ", g.vex[i]);
}
printf("\n图的邻接矩阵是:\n");
for (int i = 0; i < g.n; i++) {
for (int j = 0; j < g.n; j++) {
if (i == j) printf("0 ");
else if (g.edge[i][j] == INF)
{
printf("INF ");
}
else {
printf("%-4d", g.edge[i][j]);
}
}
printf("\n");
}
}
void printDegree(adjGraph g)
{
printf("图中每个顶点的入度是:\n");
for (int i = 0; i < g.n; i++) {
int indegree = 0;
for (int j = 0; j < g.n; j++) {
if (g.edge[j][i] != 0 && g.edge[j][i] != INF) {
indegree++;
}
}
printf("%c: %d \n", g.vex[i], indegree);
}
printf("图中每个顶点的出度是:\n");
for (int i = 0; i < g.n; i++) {
int outdegree = 0;
for (int j = 0; j < g.n; j++) {
if (g.edge[i][j] != 0&& g.edge[i][j] != INF) {
outdegree++;
}
}
printf("%c: %d \n", g.vex[i], outdegree);
}
}
样例:
? 对每一个顶点建立一个单链表,将同一个顶点发出的边链接在一个称为边链表的单链表中。
头插法:
? ? ??