线性表中我们把数据元素叫元素,树中将数据元素叫结点,在图中的数据元素我们称之为顶点(Vertex)。
线性表中可以没有数据元素,称之为空表。树中可以没有结点,叫做空树。但图没有空图。
线性表中,相邻的数据元素之间具有线性关系,树结构中,相邻两层的结点具有层次关系,而图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以为空。
无向边:若顶点vi到vj之间的边没有方向,则称这条边为五向边(Edge),用无序偶对(vi,vj)来表示。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。
有向边:若从顶点vi到vj的边有方向,则称这条边为有向边 ,也称为弧(Arc),用有序偶<vi,vj>来表示,vi称为弧尾(Tail),vj称为弧头(Head)。顶点之间的边都是有向边,则称该图为有向图。
在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。
在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有n*(n-1)/2条边。
在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。
图有两种存储方式:
邻接矩阵:(二维数组)一维数组存顶点信息,二维数组存边的信息
无向图连接矩阵一定对称、有向图不一定对称
邻接表:(链表)
邻接矩阵实现图的插入和删除
# define SIZE 10 class Graph { public: Graph(); ~Graph(); void InsertVertex(char v); void InsertEdge(char v1, char v2); void PrintGraph(); int GetVertexInder(char v); void deleteEdge(char v1,char v2); void delVertex(char v); private: int m_MaxVertex; int m_NumVertex; int m_NumEdge; char* m_VertexArr; int m_Edge[SIZE][SIZE]; }; Graph::Graph() { m_MaxVertex = SIZE; m_NumVertex = m_NumEdge = 0; for (int i = 0; i < m_MaxVertex; ++i) { for (int j = 0; j < m_MaxVertex; ++j) { m_Edge[i][j] = 0; } } m_VertexArr = new char[m_MaxVertex]; } Graph::~Graph() { if (m_VertexArr != nullptr) { delete[]m_VertexArr; m_VertexArr = nullptr; } m_NumEdge = m_NumVertex = 0; } void Graph::InsertVertex(char v)//插入顶点 { if (m_NumVertex >= m_MaxVertex) { return; } m_VertexArr[m_NumVertex++] = v; } int Graph::GetVertexInder(char v) { for (int i = 0; i < m_NumVertex; i++) { if (v == m_VertexArr[i]) { return i; } } return -1; } void Graph::InsertEdge(char v1, char v2) { int p1 = GetVertexInder(v1); int p2 = GetVertexInder(v2); if (p1 == -1 || p2 == -1) { return; } m_Edge[p1][p2] = m_Edge[p2][p1] = 1; m_NumEdge++; } void Graph::PrintGraph() { int i, j; for (i = 0; i < m_NumVertex; i++) { cout << " "<<m_VertexArr[i] << " "; } cout << endl; for (i = 0; i < m_NumVertex; ++i) { cout << m_VertexArr[i] << " "; for (j = 0; j < m_NumVertex; ++j) { cout << m_Edge[i][j] << " "; } cout << endl; } } void Graph::deleteEdge(char v1, char v2) { int p1 = GetVertexInder(v1); int p2 = GetVertexInder(v2); if (p1 == -1 || p2 == -1) { return; } m_Edge[p1][p2] = m_Edge[p2][p1] = 0; m_NumEdge--; } void Graph::delVertex(char v) { //第一种删除方法,删除C。将C所在行和例后面的行和列依次前移 //int p1 = GetVertexInder(v); //if (p1 == -1) // return; //int delEdge = 0; //int i,j; //for (i = 0; i < m_NumVertex; ++i) //{ // if (m_Edge[p1][i] == 1) // { // delEdge++; // } //} //for (i = p1; i < m_NumVertex-1; ++i) //{ // m_VertexArr[i] = m_VertexArr[i + 1]; //} //for (i = p1; i < m_NumVertex-1; ++i) //{ // for (j = 0; j < m_NumVertex; ++j) // { // m_Edge[j][i] = m_Edge[j][i + 1];//移动列 // } //} //for (i = p1; i < m_NumVertex - 1; ++i) //{ // for (j = 0; j < m_NumVertex - 1; j++) // { // m_Edge[i][j] = m_Edge[i + 1][j];//移动行 // } //} //m_NumEdge = m_NumEdge - delEdge; //m_NumVertex--; //第二种删除方法:替换法,删除哪一行或列用最后一行或列对它进行替换。 int p1 = GetVertexInder(v); if (p1 == -1) return; int delEdge = 0; int i,j; for (i = 0; i < m_NumVertex; ++i) { if (m_Edge[p1][i] == 1) { delEdge++; } } m_VertexArr[p1] = m_VertexArr[m_NumVertex - 1]; for (i = 0; i < m_NumVertex; i++) { m_Edge[i][p1] = m_Edge[i][m_NumVertex - 1]; } for (i = 0; i < m_NumVertex - 1; i++) { m_Edge[p1][i] = m_Edge[m_NumVertex - 1][i]; } m_NumEdge = m_NumEdge - delEdge; m_NumVertex--; } void main() { Graph g; g.InsertVertex('A'); g.InsertVertex('B'); g.InsertVertex('C'); g.InsertVertex('D'); g.InsertEdge('A', 'B'); g.InsertEdge('A', 'D'); g.InsertEdge('B', 'C'); g.InsertEdge('B', 'D'); g.InsertEdge('C', 'D'); g.PrintGraph(); g.deleteEdge('A', 'B'); g.PrintGraph(); g.delVertex('C'); g.PrintGraph(); }
运行结果:
邻接表:
/*邻接表*/ #define SIZE 10 class Edge//边 { public: Edge():m_next(nullptr){} Edge(char v):m_destindex(v) ,m_next(nullptr) {} int m_destindex;//邻接顶点的下标 Edge* m_next;//下一个邻接顶点的结点的地址 }; class vertex//顶点 { public: vertex():m_list(nullptr){} vertex(char v) :m_VerValue(v), m_list(nullptr){} int m_VerValue;//顶点的值 Edge* m_list;//之相邻顶点的链表 }; class GraphLink//图 { public: GraphLink(); ~GraphLink(); void InsertVertex(char v); void InsertEdge(char v1, char v2); void PrintGraph(); void DelVertex(char v); void DelEdge(char v1, char v2); int GetVertexIndex(char v); private: int m_MaxVertex; int m_NumVertex; int m_NumEdge; vertex* m_VerArr; }; GraphLink::GraphLink()//构造函数 { m_MaxVertex = SIZE;//最大顶点数 m_NumVertex = m_NumEdge = 0;//实际顶点数 m_VerArr = new vertex [m_MaxVertex];//new一个m_verArr数组 } GraphLink::~GraphLink()//析构函数 { if (m_VerArr != nullptr) { delete[]m_VerArr; m_VerArr = nullptr; } } void GraphLink::InsertVertex(char v) { if (m_NumVertex >= m_MaxVertex) return; m_VerArr[m_NumVertex++].m_VerValue = v;//m_NumVertexshiji顶点数,可以充当数组下标 } void GraphLink::InsertEdge(char v1, char v2) { int p1 = GetVertexIndex(v1); int p2 = GetVertexIndex(v2); if (p1 == -1 || p2 == -1) { return; } //V1->V2 即是在V1的边链表中插入值为p2的边节点 Edge* edge = new Edge(p2); edge->m_next = m_VerArr[p1].m_list; m_VerArr[p1].m_list = edge; edge = new Edge(p1); edge->m_next = m_VerArr[p2].m_list; m_VerArr[p2].m_list = edge; m_NumEdge++; } int GraphLink::GetVertexIndex(char v) { for (int i = 0; i < m_NumVertex; i++) { if (v == m_VerArr[i].m_VerValue) { return i; } } return -1; } void GraphLink::DelEdge(char v1, char v2) { int p1 = GetVertexIndex(v1); int p2 = GetVertexIndex(v2); if (p1 == -1 || p2 == -1) { return; } Edge* pf = nullptr; Edge* p = m_VerArr[p1].m_list; while (p != nullptr && p->m_destindex != p2) { pf = p; p = p->m_next; } if (p == nullptr)//v1到v2没有边 { return; } if (pf == nullptr)//if(p==m_verArr[p1].m_list) { m_VerArr[p1].m_list = p->m_next; } else { pf->m_next = p->m_next; } delete p; pf = nullptr; p = m_VerArr[p2].m_list; while (p->m_destindex != p1) { pf = p; p = p->m_next; } if (pf == nullptr) { m_VerArr[p2].m_list = p->m_next; } else { pf->m_next = p->m_next; } delete p; p = nullptr; m_NumEdge--; } void GraphLink::DelVertex(char v) { int pindex = GetVertexIndex(v); if (pindex == -1) { return; } Edge* p = m_VerArr[pindex].m_list; char destvalue; while (p != nullptr) { destvalue = m_VerArr[p->m_destindex].m_VerValue;//获得邻接顶点 DelEdge(v, destvalue); p = m_VerArr[pindex].m_list; } //覆盖 m_NumVertex--; m_VerArr[pindex].m_VerValue = m_VerArr[m_NumVertex].m_VerValue; m_VerArr[pindex].m_list = m_VerArr[m_NumVertex].m_list; //修改 Edge* q = nullptr; p = m_VerArr[pindex].m_list; while (p != nullptr) { int k = p->m_destindex; q = m_VerArr[k].m_list;//找到相关联的顶点的边链表 while (q) { if (q->m_destindex == m_NumVertex) { q->m_destindex = pindex; break; } q = q->m_next; } p = p->m_next; } } void GraphLink::PrintGraph() { Edge* p = nullptr; for (int i = 0; i < m_NumVertex; i++) { cout << i << " " << (char)m_VerArr[i].m_VerValue << ":"; p = m_VerArr[i].m_list; while (p) { cout << p->m_destindex << "->"; p = p->m_next; } cout << "nul" << endl; } } void main() { GraphLink lg; lg.InsertVertex('A'); lg.InsertVertex('B'); lg.InsertVertex('C'); lg.InsertVertex('D'); lg.InsertEdge('A', 'B'); lg.InsertEdge('A', 'C'); lg.InsertEdge('A', 'D'); lg.InsertEdge('B', 'C'); lg.InsertEdge('C', 'D'); lg.PrintGraph(); cout << "DelEdge" << endl; lg.DelEdge('A', 'D'); lg.PrintGraph(); cout << "DelGraph" << endl; lg.DelVertex('A'); lg.PrintGraph(); }
运行结果: