图遍历生成树演示
程序的功能:
通过对连通图和非连通图的遍历,可以访问图中全部结点。可以输出该图的邻接矩阵以及该图的邻接表,可以进行广度优先遍历或深度优先遍历生成树。可以实现删除一个结点的操作。
输入的形式和输入值的范围:输入顶点个数以及边的个数,每条边的权值默认为1,每个都是整型变量,即int型变量。
输出的形式:
1.如果输出邻接矩阵,是等于顶点个数的行数与列数,如果权值不存在即输出0
2.如果输出的是邻接表,即用箭头指向,边表指向与顶点存在边的顶点
3.广度与深度优先输出的是一行整型数字,并且该整型数字为遍历生成树的先序遍历序列
测试数据:依照要求输入符合输入形式的顶点与边的个数,权值默认为1,对连通图和非连通图进行测试,分别进行深度优先和广度优先遍历和插入删除操作。
#include <stdio.h>
#include <stdlib.h>
#define MAX_VERtEX_NUM 20 //顶点的最大个数
#define VRType int //表示顶点之间的关系的变量类型
#define VertexType int //图中顶点的数据类型
#define InfoType char //存储弧或者边额外信息的指针变量类型
#define int_max 10000
#define max 20
typedef enum { false, true }bool; //定义bool型常量
bool visited[MAX_VERtEX_NUM]; //设置全局数组,记录标记顶点是否被访问过
typedef struct {
VRType adj; //对于无权图,用 1 或 0 表示是否相邻;对于带权图,直接为权值。
InfoType* info; //弧或边额外含有的信息指针
}ArcCell, AdjMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM];
typedef struct {
VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据
AdjMatrix arcs; //二维数组,记录顶点之间的关系
int vexnum, arcnum; //记录图的顶点数和弧(边)数
}MGraph;
typedef struct CSNode {//孩子兄弟表示法的链表结点结构
VertexType data;
struct CSNode* lchild;//孩子结点
struct CSNode* nextsibling;//兄弟结点
}*CSTree, CSNode;//根据顶点本身数据,判断出顶点在二维数组中的位置
typedef struct Queue {
CSTree data;//队列中存放的为树结点
struct Queue* next;
}Queue;
int LocateVex(MGraph G, VertexType v) {//遍历一维数组,找到变量v,返回位置i
int i = 0;
for (; i < G.vexnum; i++) {
if (G.vexs[i] == v) {
break;
}
}//如果找不到,输出提示语句,返回-1
if (i > G.vexnum) {
printf("no such vertex.\n");
return -1;
}
return i;
}//构造无向图
void CreateDN(MGraph* G) {
int i = 0;
printf(" ***********************************************\n");
printf(" ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 创建无向图 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("请输入图G的顶点和弧的个数如:(4 4),但不包括()\n");
scanf("%d %d", &(G->vexnum), &(G->arcnum));
system("cls");
printf(" ***********************************************\n");
printf(" ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 正在创建无向图 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
for (i = 0;i < 20;i++)//初始化
{
if (i < G->vexnum)
G->vexs[i] = i + 1;
else
G->vexs[i] = 0;
}
for (i = 0;i < G->vexnum;++i)
{
printf("按照您输入的顶点个数,已为您创建第%d顶点为 %d \n", i + 1, i + 1);
}
printf("按任意键继续");
system("pause");
system("cls");
printf(" ***********************************************\n");
printf(" ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 正在创建无向图 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
for (i = 0; i < G->vexnum; i++) {
for (int j = 0; j < G->vexnum; j++) {
G->arcs[i][j].adj = 0;
G->arcs[i][j].info = NULL;
}
}
for (i = 0; i < G->arcnum; i++) {//创建邻接矩阵
int v1, v2;
printf("输入第%d条边所依附的顶点如:(1 5),但不包括(),默认权值为1\n", i + 1);
scanf("%d %d", &v1, &v2);
int n = LocateVex(*G, v1);
int m = LocateVex(*G, v2);
if (m == -1 || n == -1) {
printf("无此顶点\n");
return;
}
G->arcs[n][m].adj = 1;
G->arcs[m][n].adj = 1;//无向图的二阶矩阵沿主对角线对称
}
printf("创建邻接矩阵成功,按任意键继续");
system("pause");
system("cls");
}
int FirstAdjVex(MGraph G, int v)
{
//查找与数组下标为v的顶点之间有边的顶点,返回它在数组中的下标
for (int i = 0; i < G.vexnum; i++) {
if (G.arcs[v][i].adj) {
return i;
}
}
return -1;
}
int NextAdjVex(MGraph G, int v, int w)
{
//从前一个访问位置w的下一个位置开始,查找之间有边的顶点
for (int i = w + 1; i < G.vexnum; i++) {
if (G.arcs[v][i].adj) {
return i;
}
}
return -1;
}
//初始化队列
typedef struct arcnode//图的邻接表存储 弧结点
{
int adjvex;//该弧指向的顶点的位置
struct arcnode* nextarc;//弧尾相同的下一条弧
char* info;//该弧信息
}arcnode;
typedef struct vnode//邻接链表顶点----头接点
{
int data;//顶点信息
arcnode* firstarc;//指向第一条依附该结点的弧的指针
}vnode, adjlist;
typedef struct algraph//邻接表的图的定义
{
adjlist vertices[max];//邻接表
int vexnum, arcnum;//图的顶点,弧数
int kind;
}algraph;
void InitQueue(Queue** Q) {
(*Q) = (Queue*)malloc(sizeof(Queue));
(*Q)->next = NULL;
}
//结点v进队列
void EnQueue(Queue** Q, CSTree T) {
Queue* element = (Queue*)malloc(sizeof(Queue));
element->data = T;
element->next = NULL;
Queue* temp = (*Q);
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = element;
}
//队头元素出队列
void DeQueue(Queue** Q, CSTree* u) {
(*u) = (*Q)->next->data;
(*Q)->next = (*Q)->next->next;
}
//判断队列是否为空
bool QueueEmpty(Queue* Q) {
if (Q->next == NULL) {
return true;
}
return false;
}
void ljjzprint(MGraph G)//输出邻接矩阵
{
int i, j;
for (i = 0;i < G.vexnum;i++)
{
for (j = 0;j < G.vexnum;j++)
printf("%d ", G.arcs[i][j].adj);
printf("\n");
}
}
//*************邻接表表示图*********************************
int creatadj(algraph* gra, MGraph G)//用邻接表存储图
{
int i = 0, j = 0;
arcnode* arc, * tem, * p;
for (j = 0, i = 0;i < 20;i++)
{
if (G.vexs[i] != 0)
{
gra->vertices[j].data = G.vexs[i];
gra->vertices[j].firstarc = NULL;//初始化邻接链表的表头指针
j++;
}
}
for (i = 0;i < G.vexnum;i++)
{
for (j = 0;j < G.vexnum;j++)
{
if (gra->vertices[i].firstarc == NULL)
{
if (G.arcs[i][j].adj != 0 && j != G.vexnum)
{
arc = (arcnode*)malloc(sizeof(arcnode));
arc->adjvex = j;
gra->vertices[i].firstarc = arc;
arc->nextarc = NULL;
p = arc;
++j;
while (G.arcs[i][j].adj != 0 && j != G.vexnum)
{
tem = (arcnode*)malloc(sizeof(arcnode));
tem->adjvex = j;
gra->vertices[i].firstarc = tem;
tem->nextarc = arc;
arc = tem;
j++;
}
--j;
}
}
else
{
if (G.arcs[i][j].adj != 0 && j != G.vexnum)
{
arc = (arcnode*)malloc(sizeof(arcnode));
arc->adjvex = j;
p->nextarc = arc;
arc->nextarc = NULL;
p = arc;
}
}
}
}
gra->vexnum = G.vexnum;
gra->arcnum = G.arcnum;
return 1;
}
//******************************************************
void adjprint(algraph gra)//输出邻接表
{
int i, p1;
for (i = 0;i < gra.vexnum;i++)
{
arcnode* p;
printf("%d->", gra.vertices[i].data);
p = gra.vertices[i].firstarc;
while (p != NULL)
{
p1 = p->adjvex;
if (p->nextarc != NULL)printf("%d->", gra.vertices[p1].data);
else printf("%d", gra.vertices[p1].data);
p = p->nextarc;
}
printf("\n");
}
}
void BFSTree(MGraph G, int v, CSTree* T) {
CSTree q = NULL;
Queue* Q;
InitQueue(&Q);
EnQueue(&Q, (*T)); //根结点入队
while (!QueueEmpty(Q)) {//当队列为空时,证明遍历完成
bool first = true;
DeQueue(&Q, &q);//队列首个结点出队
int v = LocateVex(G, q->data); //判断结点中的数据在数组中的具体位置
visited[v] = true; //已经访问过的更改其标志位
//遍历以出队结点为起始点的所有邻接点
for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
//标志位为false,证明未遍历过
if (!visited[w]) {
//新建一个结点 p,存放当前遍历的顶点
CSTree p = (CSTree)malloc(sizeof(CSNode));
p->data = G.vexs[w];
p->lchild = NULL;
p->nextsibling = NULL;
//当前结点入队
EnQueue(&Q, p);
//更改标志位
visited[w] = true;
//如果是出队顶点的第一个邻接点,设置p结点为其左孩子
if (first) {
q->lchild = p;
first = false;
}
//否则设置其为兄弟结点
else {
q->nextsibling = p;
}
q = p;
}
}
}
}
//广度优先搜索生成森林并转化为二叉树
void BFSForest(MGraph G, CSTree* T) {
(*T) = NULL;
//每个顶点的标记为初始化为false
for (int v = 0; v < G.vexnum; v++) {
visited[v] = false;
}
CSTree q = NULL;
//遍历图中所有的顶点
for (int v = 0; v < G.vexnum; v++) {
//如果该顶点的标记位为false,证明未访问过
if (!(visited[v])) {
//新建一个结点,表示该顶点
CSTree p = (CSTree)malloc(sizeof(CSNode));
p->data = G.vexs[v];
p->lchild = NULL;
p->nextsibling = NULL;
//如果树未空,则该顶点作为树的树根
if (!(*T)) {
(*T) = p;
}
//该顶点作为树根的兄弟结点
else {
q->nextsibling = p;
}
//每次都要把q指针指向新的结点,为下次添加结点做铺垫
q = p;
//以该结点为起始点,构建广度优先生成树
BFSTree(G, v, &p);
}
}
}
void DFSTree(MGraph G, int v, CSTree* T) {
//将正在访问的该顶点的标志位设为true
visited[v] = true;
bool first = true;
CSTree q = NULL;
//依次遍历该顶点的所有邻接点
for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
//如果该临界点标志位为false,说明还未访问
if (!visited[w]) {
//为该邻接点初始化为结点
CSTree p = (CSTree)malloc(sizeof(CSNode));
p->data = G.vexs[w];
p->lchild = NULL;
p->nextsibling = NULL;
//该结点的第一个邻接点作为孩子结点,其它邻接点作为孩子结点的兄弟结点
if (first) {
(*T)->lchild = p;
first = false;
}
else {//否则,为兄弟结点
q->nextsibling = p;
}
q = p;
//以当前访问的顶点为树根,继续访问其邻接点
DFSTree(G, w, &q);
}
}
}
void DFSForest(MGraph G, CSTree* T) {//深度优先搜索生成森林并转化为二叉树
(*T) = NULL;
//每个顶点的标记为初始化为false
for (int v = 0; v < G.vexnum; v++) {
visited[v] = false;
}
CSTree q = NULL;
//遍历每个顶点作为初始点,建立深度优先生成树
for (int v = 0; v < G.vexnum; v++) {
//如果该顶点的标记位为false,证明未访问过
if (!(visited[v])) {
//新建一个结点,表示该顶点
CSTree p = (CSTree)malloc(sizeof(CSNode));
p->data = G.vexs[v];
p->lchild = NULL;
p->nextsibling = NULL;
//如果树未空,则该顶点作为树的树根
if (!(*T)) {
(*T) = p;
}
//该顶点作为树根的兄弟结点
else {
q->nextsibling = p;
}
//每次都要把q指针指向新的结点,为下次添加结点做铺垫
q = p;
//以该结点为起始点,构建深度优先生成树
DFSTree(G, v, &p);
}
}
}
void PreOrderTraverse(CSTree T) {//前序遍历二叉树
if (T) {
printf("%d ", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->nextsibling);
}
return;
}
int deletedian(MGraph * G)//删除结点
{
int v1, v2;
int x, y, w, k, i, j, g1, g2, vex[20], m, i1;
for (i = 0;i < 20;i++)
{
if (i < G->vexnum)
vex[i] = i + 1;
else
vex[i] = 0;
}
printf("请输入你想删除的结点个数和删除结点后减少的弧的个数,例如:(2 3),不包括( )\n");
scanf("%d %d", &x, &y);
system("cls");
g1 = G->vexnum;
g2 = G->arcnum;
G->vexnum = G->vexnum - x;
G->arcnum = G->arcnum - y;
for (w = 0;w < g1;w++)
{
printf("原来的的第%d顶点为 %d \n", w + 1, w + 1);
}
for (i = 0;i < x;i++)
{
printf("输入你想删除的顶点\n");
scanf("%d", &m);
vex[m - 1] = 0;
for(j=0;j<g1-m;j++)
G->vexs[m - 1] = G->vexs[m];
for (i1 = m - 1;i1 < g1;i1++)
for (j = 0;j < g1 - m;j++)
G->vexs[m-1+j] = G->vexs[m+j];
for (i1 = 0;i1 < g1;i1++)
for (j = m - 1;j < g1;j++)
{
G->arcs[i1][j] = G->arcs[i1][j + 1];
}
}
system("cls");
for (w = 0, i = 0;i < 20;i++)
{
if (vex[w] != 0)
{
printf("现在的第%d顶点为 %d \n", i + 1, vex[w]);
w++;
}
else
w++;
}
printf("\n");
printf("图G邻接矩阵删除点成功");
return G->vexnum;
}
int main()
{
system("color F0");
MGraph G;//建立一个图的变量
CreateDN(&G);//初始化图
CSTree T;
algraph gra;
creatadj(&gra, G);
int i, j, d, g[20][20];
char a = 'a';
printf(" ***********************************************\n");
printf(" ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("************************************************\n");
printf("** 1.显示该图的邻接矩阵 ***\n");
printf("************************************************\n");
printf("** 2.显示该图的邻接表 ***\n");
printf("************************************************\n");
printf("** 3.广度优先遍历 ***\n");
printf("************************************************\n");
printf("** 4.深度优先遍历 ***\n");
printf("************************************************\n");
printf("** 5.删除一个结点 ***\n");
printf("************************************************\n");
printf("^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ \n");
printf("************************************************\n");
int s, r, y = 1, c;
char y2;
while (y == 1)
{
printf("请输入你要选择的操作\n");
scanf("%d", &s);
switch (s)
{
case 1:
system("cls");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("** 邻接矩阵显示如下: **\n");
printf("************************************************\n");
ljjzprint(G);
break;
case 2:
system("cls");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("** 邻接表显示如下: **\n");
printf("************************************************\n");
adjprint(gra);
break;
case 3:
system("cls");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("** 广度优先遍历生成树如下: **\n");
printf("************************************************\n");
BFSForest(G, &T);
PreOrderTraverse(T);
printf("\n");
break;
case 4:
system("cls");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
printf("** 深度优先遍历生成树如下: **\n");
printf("************************************************\n");
DFSForest(G, &T);
PreOrderTraverse(T);
printf("\n");
break;
case 5:
{
system("cls");
system("cls");
printf(" ***********************************************\n");
printf(" _____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 正在删除顶点 ┃\n");
printf("┃____________________________________________┃\n");
printf("************************************************\n");
d = deletedian(&G);
creatadj(&gra, G);
break;
}
default:break;
}
printf("\n是否继续?若继续请输入 1 否则输入 2 :\n");
scanf("%d", &y);
if (y == 2)
break;
else
{
system("cls");
printf(" ***********************************************\n");
printf(" ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf(" ***********************************************\n");
printf(" ____________________________________________ \n");
printf("┃ ┃\n");
printf("┃ 图遍历生成树演示 ┃\n");
printf("┃____________________________________________┃\n");
printf("***********************************************\n");
printf("***********************************************\n");
printf("** 1.显示该图的邻接矩阵 **\n");
printf("***********************************************\n");
printf("** 2.显示该图的邻接表 **\n");
printf("***********************************************\n");
printf("** 3.广度优先遍历 **\n");
printf("***********************************************\n");
printf("** 4.深度优先遍历 **\n");
printf("***********************************************\n");
printf("** 5.删除一个结点 **\n");
printf("***********************************************\n");
printf("^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^ ^_^\n");
printf("***********************************************\n");
}
}}