icoding复习6
1. 邻接表1
 试在邻接表存储结构上实现图的基本操作 insert_vertex 和 insert_arc,相关定义如下:
 typedef int VertexType;
 typedef enum{
     DG, UDG
 }GraphType;
 typedef struct ArcNode{
     int adjvex;
     InfoPtr *info;
     struct ArcNode *nextarc;
 }ArcNode;
 typedef struct VNode{
     VertexType data;
     ArcNode *firstarc;
 }VNode;
 typedef struct{
     VNode vertex[MAX_VERTEX_NUM];
     int vexnum, arcnum;
     GraphType type;
 }ListGraph;
 int locate_vertex(ListGraph* G, VertexType v); //返回顶点 v 在vertex数组中的下标,如果v不存在,返回-1
 bool insert_vertex(ListGraph *G, VertexType v);
 bool insert_arc(ListGraph *G, VertexType v, VertexType w);
 当成功插入顶点或边时,函数返回true,否则(如顶点或边已存在、插入边时顶点v或w不存在)返回false。
//写下locate函数
 int locate_vertex(ListGraph *G, VertexType v){
     int i;
     for(i = 0; i < G->vexnum; i++)
         if(G->vertex[i].data == v)
             return i;
     return -1;
 } 
 #include 
 #include
 //记得加这个头文件消除黄色警告 
 #include "graph.h" //请勿删除,否则检查不通过
 bool insert_vertex(ListGraph *G, VertexType v){
     int  i = 0;
     //2个易错点: 指针置空,可以省略; 点运算符!!务必区分 
     i = locate_vertex(G, v);
     if(i != -1) return false;
     G->vertex[G->vexnum].data = v;
     G->vertex[G->vexnum].firstarc = NULL;
     G->vexnum++;
     return true; 
 }
bool insert_arc(ListGraph *G, VertexType v, VertexType w){
     int i = locate_vertex(G, v);
     int j = locate_vertex(G, w);
     
     //点不存在 
     if(i == -1 || j == -1) return false;
     //边已经存在
     ArcNode *p = G->vertex[i].firstarc;
     for(; p; p = p->nextarc)
         if(p->adjvex == j)
             return false; 
         
     ArcNode *q;
     p = G->vertex[i].firstarc;
     if(!(q = (ArcNode *)malloc(sizeof(ArcNode)))) return false;    
     q->adjvex = j;
     if(!p){
         G->vertex[i]->firstarc = q;
         q->nextarc = NULL;
     }
     else{
         q->nextarc = p->nextarc;
         p->nextarc = q; 
     }
     G->arcnum++; 
     return true;
 }
//第一次的思路
 bool insert_arc(ListGraph *G, VertexType v, VertexType w){
     int i, j;
     ArcNode *p;
     
     i = locate_vertex(G, v);
     j = locate_vertex(G, w);
     
     //判结点是否存在,不存在就返回false 
     if(i == -1|| j == -1)
         return false;
         
     //判边是否存在,存在就返回false 
     //需要注意的是p->adjvex = j这个判断条件,一个是int类型,一个是不要把这个判断条件放到for里面 
     for(p = G->vertex[i].firstarc;  p; p = p->nextarc)
         if(p->adjvex == j)     return false;
     
     //!!!!!需要注意的是这里是单项插入,不考虑有向无向
     //插入到方向就是v-->w 
 //    for(p = G->vertex[j].firstarc;  p; p = p->nextarc)
 //    if(p->adjvex == i)  return false;
    
 //    if(G->type == UDG){
 //        p->nextarc = G->vertex[j].firstarc->nextarc;
 //        p->adjvex = v;
 //        G->vertex[j].firstarc = p; 
 //    }
//!!!别忘了分配空间,这个是建立一个新的节点 
     p = (ArcNode *)malloc(sizeof(ArcNode));
     p->adjvex = j;
     G->arcnum++; 
     if(!G->vertex[i].firstarc)//空的情况 
         G->vertex[i].firstarc = p;
     else{//头插 G->vertex[i].firstarc是头结点 
         p->nextarc = G->vertex[i].firstarc->nextarc;
         G->vertex[i].firstarc = p;
     }
     return true;    
 } 
 2. 邻接表2
试在邻接表存储结构上实现图的基本操作 del_vertex,相关定义如下:
typedef int VertexType;
typedef enum{
     DG, UDG
 }GraphType;
typedef struct ArcNode{
     int adjvex;
     InfoPtr *info;
     struct ArcNode *nextarc;
 }ArcNode;
typedef struct VNode{
     VertexType data;
     ArcNode *firstarc;
 }VNode;
 typedef struct{
     VNode vertex[MAX_VERTEX_NUM];
     int vexnum, arcnum;
     GraphType type;
 }ListGraph;
int locate_vertex(ListGraph *G, VertexType v); //返回顶点 v 在vertex数组中的下标,如果v不存在,返回-1
 bool del_vertex(ListGraph *G, VertexType v); //删除顶点 v
 当成功删除顶点或边时,函数返回true,否则(如顶点或边不存在、删除边时顶点v或w不存在)返回false。
#include  
 #include 
 #include "graph.h" //请勿删除,否则检查不通过
 bool del_vertex(ListGraph* G, VertexType v){
     int i = locate_vertex(G, v), j;
     if(i == -1) return false;
     j = i;
     ArcNode *p, *q;
     
     
     for(p = G->vertex[i].firstarc; p;){
         q = p;
         p = p->nextarc;
         free(q);
         G->arcnum--;
     } 
     free(G->vertex[i].firstarc); G->arcnum--;//在最后丢表头, 注意点, 这里不能理解为没有数据的头结点 
     
     for(; i < G->vexnum; i++)
         G->vertex[i] = G->vertex[i+1];
     G->vexnum--;
     
     for(i = 0; i < G->vexnum; i++){
         for(p = G->vertex[i].firstarc, q = p; p->adjvex != j && p ;q = p, p = p->nextarc)
             ;
         if(p->adjvex == j){
             if(p == G->vertex[i].firstarc)
                 G->vertex[i].firstarc = p->nextarc;//隐含q == p 
             else
                 q->nextarc = p->nextarc;
             free(p);
             G->arcnum--;
         } 
     }
 }
//答案如下 
 //思路整理
 //1. 定位该节点是否存在,若存在
 //2. 删除该结点以之为弧尾的链表, 挨着删,最后删除表头, 边数减少 
 //3. 结点序列前移, 结点总数减少 
 //4. 遍历邻接表找以删除结点为弧头的链, 删除... 
 bool del_vertex(ListGraph* G, VertexType v)
 {
     int i, j = locate_vertex(G, v);
     if (j == -1) //检查是否存在该节点
         return false; 
     
     //先删除从该节点出发的边和该节点
     while (G->vertex[j].firstarc) { 
         ArcNode* p = G->vertex[j].firstarc;
         if (p->nextarc) { //先free表头结点后面的
             ArcNode* q = p->nextarc;
             p->nextarc = q->nextarc;
             free(q);
         } else {
             free(p); //free表头结点
             G->vertex[j].firstarc = NULL;
         }
         G->arcnum--; //边的数量-1
     }
     G->vexnum--; //结点的数量-1
     for (i = j; i < G->vexnum; i++) { //表头结点中,后面的向前移动
         G->vertex[i] = G->vertex[i + 1];
     }
     
     //再删除到该节点的边
     for (i = 0; i < G->vexnum; i++) {
         ArcNode *p = G->vertex[i].firstarc, *pNode = NULL;
         ArcNode* q; //存储要被删掉的结点
         while (p) {
             if (p->adjvex == j) { //P的下个结点是V
                 if (!pNode) { //P是表头结点
                     q = G->vertex[i].firstarc;
                     G->vertex[i].firstarc = p->nextarc;
                 }
                 else {
                     pNode->nextarc = p->nextarc;
                     q = p;
                 }
                 p = p->nextarc;
                 free(q);
                 G->arcnum--;
             } else {
                 pNode = p;
                 p = p->nextarc;
             }
         }
     }
     return true;
 }
3. 邻接矩阵
试在邻接矩阵存储结构上实现图的基本操作 matrix_insert_vertex 和matrix_insert_arc,相关定义如下:
typedef int VertexType;
typedef enum{
     DG, UDG
 }GraphType;
typedef struct{
     VertexType vertex[MAX_VERTEX_NUM]; //顶点向量
     int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
     int vexnum, arcnum;   //图的当前顶点数和弧数
     GraphType type;     //图的种类标志
 }MatrixGraph;
int matrix_locate_vertex(MatrixGraph *MG, VertexType vex); //返回顶点 v 在vertex数组中的下标,
 //如果v不存在,返回-1
 bool matrix_insert_vertex(MatrixGraph *G, VertexType v);
 bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w);
 当成功插入顶点或边时,函数返回true,否则(如顶点或边已存在、插入边时顶点v或w不存在)返回false。
#include  
 #include "graph.h" // 请不要删除,否则检查不通过
bool matrix_insert_vertex(MatrixGraph *G, VertexType v){
     int i = matrix_locate_vertex(G, v);
     
     if(i != -1 || G->vexnum == MAX_VERTEX_NUM - 1) return false;
     
     G->vertex[G->vexnum] = v;
     for(i = 0; i < G->vexnum; i++){
         G->arcs[G->vexnum][i] = 0;
         G->arcs[i][G->vexnum] = 0;
     }
     G->arcnum++;
     return true;
 }
bool matrix_insert_arc(MatrixGraph *G, VertexType v, VertexType w){
     int i = matrix_locate_vertex(G, v);
     int j = matrix_locate_vertex(G, w);
     
     if(i == -1 || j == -1 || G->arcs[i][j] == 1) return false;
 //如果加上判断图的类型 
 //    if(G->type == UDG &&( G->arcs[i][j] == 1 || G->arcs[j][i] == 1))
 //        return false;
 //    else if(G->arcs[i][j] == 1)    
 //        return false;
     G->arcs[i][j] = 1;
     if(G->type == UDG)
         G->arcs[j][i] = 1;
     G->arcnum++;
     return true;
 }