您的位置:首页 > 理论基础 > 数据结构算法

数据结构之图(图的基本操作)

2014-04-06 18:56 435 查看
由于图的基本操作的代码较多,我放到这一章来写。图可以用两种方法来存储,但是本人偏爱链表的表示方法,所以以下代码也都是是基于邻接链表的存储方式。

/*
以下存储结构参考严蔚敏版数据结构,不懂的可以翻阅查看
*/
const int UNDIGRAPH = 0;    //无向图
const int DIGRAPH    = 1;    //有向图
const int MAX_VERTEX_NUM = 20;

typedef struct ArchNode
{
int    vertexIndex;        //该弧指向顶点在图中顶点数组的索引,对应vertexs[20]的下标
ArchNode *nextarc;         //指向下一条弧的指针
InfoTypde info;            //比如弧的权重
}ArchNode;

typedef struct Vertex
{
VertexType data;          //顶点信息
ArchNode    *firstarc;    //指向第一条弧的指针
}Vertex;

//这样定义图有个坏处,一旦定义好,图中结点的个数就固定了!
typedef struct Graph
{
Vertex *vertexs[MAX_VERTEX_NUM];    //存储顶点的数组,存放的是指向顶点的指针
int vexNum;                         //当前图中的定点数
int arcNum;                    //当前图中的弧的个数
int kind;                    //图的种类,有向图还是无向图
}Graph;


//图的创建

/*
初始条件:kind是图的类型,目前有有向图和无向图 两种.
返回值   :无。---大部分函数都无返回值,是对图的引用进行操作的
*/
void createGraph(Graph *&G,int kind)
{
if(G) G = NULL;
G = (Graph *)malloc(sizeof(struct Graph));
assert(NULL != G);
for(int i = 0; i < MAX_VERTEX_NUM; ++i)
{
G->vertexs[i] = NULL;        //初始化指向顶点的指针为NULL
}
G->kind = kind;                    //设置图的种类
G->vexNum = 0;                    //初始化图中顶点的个数
G->arcNum = 0;                    //初始化图中弧的个数
}


//图的销毁

/*
初始条件:G存在
返回值   :无。---大部分函数都无返回值,是对图的引用进行操作的
*/
void destoryGraph(Graph *&G)
{
ArchNode *cur,*next;
if(NULL == G)
return;
//遍历顶点
for(int i = 0; i < G->vexNum; ++i)
{
if(!G->vertexs[i])
continue;
next = G->vertexs[i]->firstarc;
cur  = G->vertexs[i]->firstarc;
while(cur)
{
next = cur->nextarc;
free(cur);
cur = next;
}
G->vertexs[i]->firstarc = NULL;
}
free(G);
G = NULL;
}


//向图中增加结点

//向图中增加结点
/*
初始条件:G存在,data是结点的数据值
*/
void addVertexToGraph(Graph *&G,VertexType data)
{
if(G->vexNum >= MAX_VERTEX_NUM)
{
cout << "Too many vertex!" << endl;
return ;
}
for(int i = 0; i < G->vexNum; ++i)
{
if(!G->vertexs[i])
continue;
if(G->vertexs[i]->data == data)
{
cout << "Already exists!" << endl;
return;        //不允许重复
}
}
Vertex *pVeterx;
pVeterx = (Vertex *)malloc(sizeof(struct Vertex));
pVeterx->data = data;
pVeterx->firstarc = NULL;
G->vertexs[G->vexNum] = pVeterx;
G->vexNum++;
}


//从图中删除一个结点

void delVertexFromGraph(Graph *&G,VertexType data)
{
bool haveThisVertex = false;
ArchNode *cur,*next,*temp,*pre;
Vertex *anotherVertex;
if(NULL == G)
return;
if(G->vexNum <= 0)
{
cout << "Have no vertex!" << endl;
return ;
}
for(int i = 0; i < G->vexNum; ++i)
{
if(!G->vertexs[i])
continue;
if(G->vertexs[i]->data == data)
{
haveThisVertex = true;
//以下循环用来删除顶点所指向的弧链表
next = cur = G->vertexs[i]->firstarc;
if(G->kind == DIGRAPH)    //如果是有向图
{
while(cur)
{
next = cur->nextarc;
free(cur);
G->arcNum --;    //弧的个数减一
cur = next;
}
G->vertexs[i] = NULL;
}
else if(G->kind == UNDIGRAPH)    //如果是无向图,这个麻烦点
{
while(cur)
{
//找到待删除的弧的另一个结点,将它的弧链表中指向被删除结点的弧也删掉
anotherVertex = G->vertexs[cur->vertexIndex];    //找到待删除弧对应的另一个结点
temp = anotherVertex->firstarc,pre = NULL;
while(temp)                                        //这个循环是为了删除另一个结点中保存弧信息
{
if(temp->vertexIndex == i)
{
//如果是首节点
if(NULL == pre)    //或者if(NULL == pre)
{
anotherVertex->firstarc = temp->nextarc;
free(temp);
}
else
{
pre->nextarc = temp->nextarc;
free(temp);
}
break;    //找到即停止循环
}
pre = temp;
temp = temp->nextarc;
}
next = cur->nextarc;
free(cur);
G->arcNum --;    //弧的个数减一
cur = next;
}
G->vertexs[i] = NULL;
}
for(int j = i; j < G->vexNum - 1; ++j)
{
G->vertexs[j] = G->vertexs[j + 1];
}
G->vertexs[j] = NULL;    //
G->vexNum-- ;            //结点的个数减一
break;
}
}
if(!haveThisVertex)
cout << "没有该结点!" << endl;
}


//从图中查找一个值为指定值的结点的索引


//初始条件:G存在,data是指定结点的数据值
int findVertexIndexInGraph(const Graph *G,VertexType data)
{
if(NULL == G)
return -1;
for(int i = 0; i < G->vexNum; ++i)
{
if(!G->vertexs[i])
continue;
if(G->vertexs[i]->data == data)
{
return i;
break;
}
}
return -1;
}


//向图中增加一条弧,有有向图和无向图之分

//初始条件:G存在,指定起始点,和弧的权重
void addArchToGraph(Graph *&G,VertexType startData,VertexType endData,InfoTypde weight = 0)
{
ArchNode *pArchNode,*cur;
//先要找到start和end
if(NULL == G)
return;
int startVertexIndex = findVertexIndexInGraph(G,startData);
int endVertexIndex = findVertexIndexInGraph(G,endData);
cur = G->vertexs[startVertexIndex]->firstarc;
while(cur)
{
if(cur->vertexIndex == endVertexIndex)
{
cout << "Already have this arch!" << endl;
return ;
}
cur = cur->nextarc;
}
if(startVertexIndex >= 0 && endVertexIndex >= 0)
{
if(G->kind == DIGRAPH)                                            //如果是有向图
{
pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //创建一个弧结点
pArchNode->info = weight;
pArchNode->nextarc = NULL;
pArchNode->vertexIndex = endVertexIndex;
cur = G->vertexs[startVertexIndex]->firstarc;
if(NULL == cur)
{
G->vertexs[startVertexIndex]->firstarc = pArchNode;
}
else
{
while(cur->nextarc)
{
cur = cur->nextarc;
}
cur->nextarc = pArchNode;
}
G->arcNum ++;    //弧的条数加一
}
else if(G->kind == UNDIGRAPH)    //如果是无向图
{
pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //创建一个弧结点
pArchNode->info = weight;
pArchNode->nextarc = NULL;
pArchNode->vertexIndex = endVertexIndex;
cur = G->vertexs[startVertexIndex]->firstarc;
if(NULL == cur)
{
G->vertexs[startVertexIndex]->firstarc = pArchNode;
}
else
{
while(cur->nextarc)
{
cur = cur->nextarc;
}
cur->nextarc = pArchNode;
}
pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //再创建一个弧结点
pArchNode->info = weight;
pArchNode->nextarc = NULL;
pArchNode->vertexIndex = startVertexIndex;
cur = G->vertexs[endVertexIndex]->firstarc;
if(NULL == cur)
{
G->vertexs[endVertexIndex]->firstarc = pArchNode;
}
else
{
while(cur->nextarc)
{
cur = cur->nextarc;
}
cur->nextarc = pArchNode;
}
G->arcNum ++;    //弧的条数加一
}
}
else
{
cout << "起点或终点不存在!" << endl;
return ;
}
}


//从图中删除一条弧

//初始条件:G存在,指定要删除弧连接的两个顶点
void delArchFromGraph(Graph *&G,VertexType startData,VertexType endData)
{
ArchNode *cur,*pre;
//先要找到start和end
if(NULL == G)
return;
int startVertexIndex = findVertexIndexInGraph(G,startData);
int endVertexIndex = findVertexIndexInGraph(G,endData);
if(startVertexIndex >= 0 && endVertexIndex >= 0)
{
if(G->kind == DIGRAPH)
{
cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
while(cur)
{
if(cur->vertexIndex == endVertexIndex)
{
break;
}
pre = cur;
cur = cur->nextarc;
}
if(NULL == cur)
{
cout << "这两个结点之间没有弧!" << endl;
return ;
}
else
{
if(NULL == pre)    //是首节点
G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
else
pre->nextarc = cur->nextarc;
free(cur);
G->arcNum --;
}
}
else if(G->kind == UNDIGRAPH)
{
cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
while(cur)
{
if(cur->vertexIndex == endVertexIndex)
{
break;
}
pre = cur;
cur = cur->nextarc;
}
if(NULL == cur)
{
cout << "这两个结点之间没有弧!" << endl;
return ;
}
else
{
if(NULL == pre)    //是首节点
G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
else
pre->nextarc = cur->nextarc;
free(cur);
//G->arcNum --;
}

cur = G->vertexs[endVertexIndex]->firstarc,pre = NULL;
while(cur)
{
if(cur->vertexIndex == startVertexIndex)
{
break;
}
pre = cur;
cur = cur->nextarc;
}
if(NULL == cur)
{
cout << "这两个结点之间没有弧!" << endl;
return ;
}
else
{
if(NULL == pre)    //是首节点
G->vertexs[endVertexIndex]->firstarc = cur->nextarc;
else
pre->nextarc = cur->nextarc;
free(cur);
G->arcNum --;
}
}
}
else
{
cout << "起点或终点不存在!" << endl;
return ;
}
}


//深度优先遍历

//初始条件:图G存在
void DFSdetails(const Graph *G,int i,int satusArr[])
{
ArchNode *cur;
if(satusArr[i] == 1 )
return;
cout << G->vertexs[i]->data << " ";
satusArr[i] = 1;
cur = G->vertexs[i]->firstarc;
while(cur)
{
DFSdetails(G,cur->vertexIndex,satusArr);
cur = cur->nextarc;
}
}

void DFS(const Graph *G)
{
int satusArr[MAX_VERTEX_NUM] = {0};
cout << "深度优先遍历:";
if(NULL == G)
return;
for(int i = 0; i < G->vexNum; ++i)
{
DFSdetails(G,i,satusArr);
}
cout << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: