C++实现数据结构--------(十字链表和拓扑排序)

拓扑排序的前提:有向无环图
在这里插入图片描述
总的来说:十字链表中对指针的操作太多
得到的经验: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();
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值