拓扑排序的前提:有向无环图
总的来说:十字链表中对指针的操作太多
得到的经验:1.指针必须初始化为NULL
2.当两个指针同时指向一块内存时,要释放这块内存的话,合法的操作应该是:先将一个指针置为NULL,再delete另一个指针(因为delete,就是告诉编译器这块内存已经没有被占用了,所以只能delete一次)
十字链表的结构:
顶点结点:
data表示顶点名称,
firstin表示指向第一个入度的弧结点的指针(也就是指向以该顶点为弧尾的第一个弧结点),
firstout表示指向第一个出度的弧结点的指针(也就是指向以该顶点为弧头的第一个弧结点)
弧结点:
tailvex表示当前弧结点的弧尾顶点在数组中的索引,
headvex表示当前弧结点的弧头顶点在数组中的索引,
hlink表示指向表示以这个顶点为弧头的下一个弧结点,
tlink表示指向以这个顶点为弧尾的下一条弧
代码:vs2019
#pragma once
#include<iostream>
#include<vector>
using namespace std;
#define MaxInt 32767
//十字链表实现图
template <class vexType, class arcType>
class arcNode {
private:
arcType arc; //边的权重
int tailVex; //表示该弧的弧尾顶点在数组中的位置
int headVex; //表示该弧的弧头顶点在数组中的位置
arcNode<vexType, arcType>* hlink; //表示以这个顶点为弧头的下一条弧
arcNode<vexType, arcType>* tlink; //表示以这个顶点为弧尾的下一条弧
template <class vexType, class arcType> friend class OLGraph;
template <class vexType, class arcType> friend class vexNode;
public:
arcNode() {
this->arc = 0;
this->headVex = -1;
this->tailVex = -1;
this->hlink = NULL;
this->tlink = NULL;
}
};
template <class vexType, class arcType>
class vexNode {
private:
vexType vex;
arcNode<vexType, arcType>* firstindegree; //表示以该顶点为弧尾的第一个弧结点
arcNode<vexType, arcType>* firstoutdegree;//表示以该顶点为弧头的第一个弧结点
template <class vexType, class arcType> friend class OLGraph;
public:
vexNode() {
this->vex = NULL;
this->firstindegree = NULL;
this->firstoutdegree = NULL;
}
};
template <class vexType, class arcType>
class OLGraph {
private:
vector<vexNode<vexType, arcType>> vnode;
int vexnum; //最大顶点数目,只增不减
int pvex; //当前顶点数目
public:
OLGraph(vector<vexType> ve, vector<vector<arcType>> g);
int LocateVex(vexType v);
int indegree(vexType v); //返回某个顶点的入度
int outdegree(vexType v);
bool insertEdge(vexType v1, vexType v2, arcType weight);
bool deleteEdge(vexType v1, vexType v2);
bool deleteVex(vexType v);
bool insertVex(vexType v);
vector<vexType> Topo_sort(); //拓扑排序,因为是直接用的删除,所以删除之后所有数据就没了,解决:可以先copy一份内存
void OLGraphPrint();
~OLGraph();
};
template<class vexType, class arcType>
inline OLGraph<vexType, arcType>::OLGraph(vector<vexType> ve, vector<vector<arcType>> g)
{
this->vexnum = ve.size();
this->pvex = ve.size();
//this->vnode = new vexNode<vexType, arcType>[vexnum]; //这种方法在增加结点的时候不好扩充,只能通过再new,memcpy复制
vnode.resize(vexnum);
for (int i = 0; i < vexnum; i++) {
vnode[i].vex = ve[i];
for (int j = 0; j < vexnum; j++) {
if (g[i][j] != MaxInt && g[i][j] != 0) { //得到所有出度的结点
arcNode<vexType, arcType>* newarcnode = new arcNode<vexType, arcType>;
newarcnode->arc = g[i][j];
newarcnode->headVex = i;
newarcnode->tailVex = j;
newarcnode->hlink = vnode[i].firstoutdegree;//得到所有出度的结点 //第一次为NULL,以后就是头插法
vnode[i].firstoutdegree = newarcnode;
newarcnode->tlink = vnode[j].firstindegree; //这一步重要:结点i的出度对应结点j的入度
vnode[j].firstindegree = newarcnode;
}
}
}
}
template<class vexType, class arcType>
inline int OLGraph<vexType, arcType>::LocateVex(vexType v)
{
for (int i = 0; i < vexnum; i++) {
if (v == vnode[i].vex)
return i;
}
return -1;
}
template<class vexType, class arcType>
inline int OLGraph<vexType, arcType>::indegree(vexType v)
{
int count = 0;
int i = LocateVex(v);
if (i == -1)
return -1;
arcNode<vexType, arcType>* p = vnode[i].firstindegree;
while (p) {
p = p->tlink;
count++;
}
return count;
}
template<class vexType, class arcType>
inline int OLGraph<vexType, arcType>::outdegree(vexType v)
{
int count = 0;
int i = LocateVex(v);
if (i == -1)
return -1;
arcNode<vexType, arcType>* p = vnode[i].firstoutdegree;
while (p) {
p = p->hlink;
count++;
}
return count;
}
template<class vexType, class arcType>
inline bool OLGraph<vexType, arcType>::insertEdge(vexType v1, vexType v2, arcType weight)
{
int m = LocateVex(v1);
int n = LocateVex(v2);
arcNode<vexType, arcType>* anode = new arcNode<vexType, arcType>;
anode->arc = weight;
anode->headVex = m;
anode->tailVex = n;
anode->hlink = this->vnode[m].firstoutdegree; //对于m结点是出度,对于n结点是入度
vnode[m].firstoutdegree = anode;
anode->tlink = this->vnode[n].firstindegree;
vnode[n].firstindegree = anode;
return true;
}
template<class vexType, class arcType>
inline bool OLGraph<vexType, arcType>::deleteEdge(vexType v1, vexType v2) //边的arcnode入度指针和出度指针都要调整
{
int m = LocateVex(v1);
int n = LocateVex(v2);
if (m < 0 || n < 0)
return false;
arcNode<vexType, arcType>* p2 = vnode[m].firstoutdegree; //m的出度的指针
arcNode<vexType, arcType>* p1 = vnode[n].firstindegree; //n的入度的指针
if (!p1 || !p2) //判断没有节点时的情况
return false;
if (!p1->tlink) { //只有一个入度结点的情况,就必然是要删除的那个
vnode[n].firstindegree = NULL;
}
else {
while (p1->tlink) { //多个结点的情况
if (p1->headVex == m && p1->tailVex == n) { //第一个结点就是要删除的结点
vnode[n].firstindegree = p1->tlink;
break;
}
else if (p1->tlink->headVex == m && p1->tlink->tailVex == n) { //第一个结点不是要删除的结点
p1->tlink = p1->tlink->tlink;
break;
}
else
p1 = p1->tlink;
}
}
if (!p2->hlink) { //只有一个出度结点的情况,就必然是要删除的那个
vnode[m].firstoutdegree = NULL;
delete p2;
p2 = NULL;
}
else {
while (p2->hlink) { //多个结点的情况
if (p2->headVex == m && p2->tailVex == n) { //第一个结点就是要删除的结点
vnode[m].firstoutdegree = p2->hlink;
delete p2;
p2 = NULL;
break;
}
else if (p2->hlink->headVex == m && p2->hlink->tailVex == n) { //第一个结点不是要删除的结点
arcNode<vexType, arcType>* xxp = p2->hlink;
p2->hlink = p2->hlink->hlink;
delete xxp;
xxp = NULL;
break;
}
else
p2 = p2->hlink;
}
}
return true;
}
template<class vexType, class arcType>
inline bool OLGraph<vexType, arcType>::deleteVex(vexType v)//删除所有的入度和出度关系
{
this->pvex--;
int m = LocateVex(v);
if (m == -1)
return false;
arcNode<vexType, arcType>* p1 = vnode[m].firstoutdegree; //删除出度关系
arcNode<vexType, arcType>* p3 = vnode[m].firstindegree; //删除入度关系
while (p1) {
arcNode<vexType, arcType>* xp1 = p1->hlink;
int n = p1->tailVex;
deleteEdge(vnode[m].vex,vnode[n].vex);
p1 = xp1;
}
while (p3) {
arcNode<vexType, arcType>* xp3 = p3->tlink;
int xm = p3->headVex;
deleteEdge(vnode[xm].vex, vnode[m].vex);
p3 = xp3;
}
vnode[m].vex = NULL;
vnode[m].firstindegree = NULL;
vnode[m].firstoutdegree = NULL;
return true;
}
template<class vexType, class arcType>
inline bool OLGraph<vexType, arcType>::insertVex(vexType v)
{
this->vexnum++;
this->pvex++;
vexNode<vexType, arcType> vp;
vp.firstindegree = NULL;
vp.firstoutdegree = NULL;
vp.vex = v;
vnode.push_back(vp);
return true;
}
template<class vexType, class arcType>
inline vector<vexType> OLGraph<vexType, arcType>::Topo_sort()
{
vector<vexType> vexs(vexnum);
int m = vexnum;
while (m > 0) {
for (int i = 0; i < vexnum; i++) {
if (!vnode[i].firstindegree && vnode[i].vex != NULL) {
vexs.push_back(vnode[i].vex);
cout << vnode[i].vex <<" ";
bool flag = deleteVex(vnode[i].vex);
if (!flag) exit(0);
m--;
break;
}
}
}
cout << endl;
return vexs;
}
template<class vexType, class arcType>
inline void OLGraph<vexType, arcType>::OLGraphPrint()
{
for (int i = 0; i < vexnum; i++) {
arcNode<vexType, arcType>* p = vnode[i].firstoutdegree;
while (p) {
cout << "顶点" << vnode[p->headVex].vex << "到顶点" << vnode[p->tailVex].vex << "的弧长为:" << p->arc << endl;
p = p->hlink;
}
}
}
template<class vexType, class arcType>
inline OLGraph<vexType, arcType>::~OLGraph()
{
for (int i = 0; i < vexnum; i++) {
arcNode<vexType, arcType>* p = vnode[i].firstoutdegree;
vnode[i].firstoutdegree = NULL;
if (!p)
continue;
arcNode<vexType, arcType>* p1 = vnode[p->tailVex].firstindegree;
vnode[p->tailVex].firstindegree = NULL;
//delete vnode[i].firstoutdegree;//加上这句引起错误:因为p也是指向这块内存的,这次释放之后,内存就不安全了
while (p1) {
arcNode<vexType, arcType>* newp1 = p1;
p1 = p1->tlink;
newp1 = NULL; //重点:因为要删除的结点是两个指针同时指向的,所以先让一个指针为NULL,通过另一个指针删除
}
while (p) {
arcNode<vexType, arcType>* newp = p;
p = p->hlink;
delete newp;
newp = NULL;
}
}
}
主函数:
vector<vector<int>> matrix3 = {
{0,1,1,MaxInt,MaxInt,MaxInt},
{MaxInt,0,MaxInt,MaxInt,MaxInt,1},
{MaxInt,MaxInt,0,MaxInt,MaxInt,MaxInt},
{MaxInt,MaxInt,1,0,1,MaxInt},
{MaxInt,MaxInt,MaxInt,MaxInt,0,1},
{MaxInt,MaxInt,MaxInt,MaxInt,MaxInt,0}
};
vector<char> ve3 = { 'a','b','c','d','e','f' };
OLGraph<char, int> olg2(ve3, matrix3);
olg2.OLGraphPrint();
cout << endl;
olg2.Topo_sort();