【数据结构笔记】6:无向图的邻接多重表存储结构

邻接多重表的实现。这次研讨确实有难度,除了实现这个还要完成最小生成树。

直接上代码吧。

边节点Arc.h

#ifndef ARC_H
#define ARC_H

#ifndef NULL
#define NULL 0
#endif

struct Arc
{
	bool tag;
	int weight;
	int adjVex1, adjVex2;
	Arc* nextArc1;
	Arc* nextArc2;
	Arc(int w, int ad1, int ad2, Arc* next1 = NULL, Arc* next2 = NULL);//3~5参构造器
};

Arc::Arc(int w, int ad1, int ad2, Arc* next1, Arc* next2)
{
	tag = 0;
	weight = w;
	adjVex1 = ad1;
	adjVex2 = ad2;
	nextArc1 = next1;
	nextArc2 = next2;
}

#endif

顶点节点Vex.h

#ifndef VEX_H
#define VEX_H
#include "Arc.h"
struct Vex
{
	char data;
	Arc* firstArc;

	Vex();
	Vex(char myData, Arc* myFirstArc);
};

Vex::Vex()//无参的构造器
{
	data = '?';
	firstArc = NULL;
}

Vex::Vex(char myData, Arc* myFirstArc) //给1~2个参数的构造器
{
	data = myData;
	firstArc = myFirstArc;
}
#endif

邻接多重表NetWork.h

#ifndef NETWORK_H
#define NETWORK_H
#include "Vex.h"
#include 
using namespace std;
struct NetWork
{
	Vex* arrayVex;
	int size;

	NetWork(int mySize, char myVex[], int **myArc);//构造函数
	void DeleteEdge(int a, int b);//删除a<->b这条边
	void InsertEdge(int a, int b,int numK);//插入a<->b这条边
	void ChangeEdge(int a, int b, int numK);//修改a<->b这条边的权值
	void Show();//显示
};

//3参数构造器
NetWork::NetWork(int mySize, char myVex[], int **myArc) 
{
	arrayVex = new Vex[size = mySize]; //分配顶点数组的空间
	for (int i = 0; i < size; i++)
	{
		arrayVex[i].data = myVex[i]; //顶点的字符
	}

	Arc *q;//辅助指针,q用于记录new对象的地址
	int numK;//辅助数字,简化计算

	//该循环建立全部边节点
	for (int i = 0; i < size; i++)
	{
		for (int j = i+1; j < size; j++)
		{
			numK = *((int *)myArc + size*i + j); //即numK=myArc[i][j]
			if (numK>0) //如果存在这条边
			{
				q = new Arc(numK, i, j);//建立这个边
				q->nextArc1 = arrayVex[i].firstArc;//i的first边一定具有i,可以作为新边的next1
				q->nextArc2 = arrayVex[j].firstArc;//j的first边一定具有j,可以作为新边的next2
				arrayVex[i].firstArc = q;//头插这条边
				arrayVex[j].firstArc = q;//头插这条边
			}
			//如果不存在这条边,什么都不做
		}
	}
}

//删除边a<->b
void NetWork::DeleteEdge(int a, int b)
{
	if (a == b || a < 0 || b < 0 || a >= size || b >= size)
	{
		cout << "输入不合法!" << endl;
		return;
	}
	//find记录是否找到a->b,如果找不到的话就不需要找b->a了
	//next记录q(或r)是p的next1还是next2
	bool find = 0,next=0;
	int c;
	Arc* p,*q,*r;
	if (a > b)//交换使得ab(从a开始找a<->b),改指针而暂时不删边节点
	q = arrayVex[a].firstArc;
	if (q == NULL)
	{
		cout << "要删除的边不存在" << endl;
		return;
	}
	if (q->adjVex1 == a && q->adjVex2 == b)//如果第一个边节点就是
	{
		arrayVex[a].firstArc = q->nextArc1;
		find = 1;
	}
	else//如果不是第一个边节点的话
	{
		//先初始化,p在q前
		p = arrayVex[a].firstArc;
		if (p->adjVex1 == a)
		{
			q = p->nextArc1;
			next = 0;//表示q是p的next1
		}
		else
		{
			q = p->nextArc2;
			next = 1;//表示q是p的next2
		}
		//然后进行循环
		while (q != NULL)
		{
			if (q->adjVex1 == a && q->adjVex2 != b)//即如果是a->非b
			{
				q = q->nextArc1;//q向下走
				//p紧随其后,但是p向下还是向右才能找到q要看next的记录了
				if (next == 0)
					p = p->nextArc1;
				else
					p = p->nextArc2;
				next = 0;//下一次,p要向下走才能找到q
			}
			else if (q->adjVex2 == a)//即如果是非b->a(因为b比a大所以adjVex2==a时adjVex1一定不是b)
			{
				q = q->nextArc2;//q向右走
				//p紧随其后,但是p向下还是向右才能找到q要看next的记录了
				if (next == 0)
					p = p->nextArc1;
				else
					p = p->nextArc2;
				next = 1;//下一次,p要向右走才能找到q
			}
			else//能运行到这时一定找到了a->b
			{
				if (next == 0)//p要向下走才能找到q
					p->nextArc1 = q->nextArc1;
				else//p要向右走才能找到q
					p->nextArc2 = q->nextArc1;
				find = 1;//找到了a->b
				break;//做完,跳出循环
			}
		}
	}
	
	if (find == 0)//如果从a找不到a<->b,那说明这条边并不存在
	{
		cout << "要删除的边不存在" << endl;
		return;
	}

	//再考虑b->a(从b开始找a<->b),改指针并且删边节点q==r
	if (arrayVex[b].firstArc->adjVex1 == a && arrayVex[b].firstArc->adjVex1 == b)//如果第一个边节点就是
	{
		arrayVex[b].firstArc = arrayVex[b].firstArc->nextArc2;
	}
	else//如果不是第一个边节点的话
	{
		p = arrayVex[b].firstArc;
		if (p->adjVex1 == b)
		{
			r = p->nextArc1;
			next = 0;
		}
		else
		{
			r = p->nextArc2;
			next = 1;
		}
		while (r != NULL)
		{
			if (r->adjVex1 == b)//即如果是b->?(?显然不是a)
			{
				r = r->nextArc1;//r向下走
				if (next == 0)
					p = p->nextArc1;
				else
					p = p->nextArc2;
				next = 0;//下次p要向下走才能找到r
			}
			else if (r->adjVex1 != a && r->adjVex2==b)//即如果是非a->b
			{
				r = r->nextArc2;//r向右走
				if (next == 0)
					p = p->nextArc1;
				else
					p = p->nextArc2;
				next = 1;//下次p要向右走才能找到r
			}
			else//r找到了那条边,即r==q
			{
				if (next == 0)//p要向下走才能找到r
					p->nextArc1 = r->nextArc2;
				else//p要向右走才能找到r
					p->nextArc2 = r->nextArc2;
				delete q;//也就是delete r
				break;//做完,跳出循环
			}
		}
	}
}


//插入边a<->b
void NetWork::InsertEdge(int a, int b,int numK)
{
	if (a == b || a < 0 || b < 0 || a >= size || b >= size)
	{
		cout << "输入不合法!" << endl;
		return;
	}

	int c;
	Arc *p,*q;
	if (a > b)//交换使得ab,只要检查从a是否能找到a<->b
	p = arrayVex[a].firstArc;
	while (p != NULL)
	{
		if (p->adjVex1 == a && p->adjVex2 != b)//即a<->非b
			p = p->nextArc1;//向下走
		else if (p->adjVex2 == a)//即非b<->a
			p = p->nextArc2;//向右走
		else//找到了a<->b
			break;
	}

	if (p != NULL)//如果找到了
	{
		cout << "要插入的边已经存在" << endl;
		return;
	}
	else//如果没找到,做插入
	{
		q = new Arc(numK, a, b);//建立这个边
		q->nextArc1 = arrayVex[a].firstArc;//i的first边一定具有i,可以作为新边的next1
		q->nextArc2 = arrayVex[b].firstArc;//j的first边一定具有j,可以作为新边的next2
		arrayVex[a].firstArc = q;//头插这条边
		arrayVex[b].firstArc = q;//头插这条边
	}
}


//修改a<->b这条边的权值
void NetWork::ChangeEdge(int a, int b, int numK)
{
	if (a == b || a < 0 || b < 0 || a >= size || b >= size)
	{
		cout << "输入不合法!" << endl;
		return;
	}

	int c;
	Arc *p;
	if (a > b)//交换使得ab,只要检查从a是否能找到a<->b
	p = arrayVex[a].firstArc;
	while (p != NULL)
	{
		if (p->adjVex1 == a && p->adjVex2 != b)//即a<->非b
			p = p->nextArc1;//向下走
		else if (p->adjVex2 == a)//即非b<->a
			p = p->nextArc2;//向右走
		else//找到了a<->b
			break;
	}

	if (p != NULL)//如果找到了
	{
		p->weight = numK;
	}
	else//如果没找到
	{
		cout << "要修改的边不存在" << endl;
	}
}

//显示
void NetWork::Show()
{
	Arc* p;
	cout << "无向图有" << size << "个点,分别为:";
	for (int i = 0; i < size; i++)
		cout << arrayVex[i].data << " ";
	cout << endl;
	for (int i = 0; i < size; i++)
	{
		cout<<"和" << arrayVex[i].data << "有关的边:";
		p = arrayVex[i].firstArc;
		while (p != NULL)
		{
			cout << arrayVex[p->adjVex1].data << "<--"<weight<<"-->" << arrayVex[p->adjVex2].data << ",";
			if (p->adjVex1 == i)//判断向下还是向右走
				p = p->nextArc1;
			else
				p = p->nextArc2;
		}
		cout << endl;
	}
}

#endif

主程序lzh2.cpp

// lzh2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "NetWork.h"

int _tmain(int argc, _TCHAR* argv[])
{
	char a[5] = { 'A', 'B', 'C', 'D', 'E' };
	int b[5][5] = { 
		{ 0, 1, 3, 0, 0 }, 
		{ 1, 0, 0, 0, 1 }, 
		{ 3, 0, 0, 2, 0 }, 
		{ 0, 0, 2, 0, 9 }, 
		{ 0, 1, 0, 9, 0 } };
	NetWork *k = new NetWork(5, a, (int**)b);
	k->Show();

	cout<4即C<->E" << endl;
	k->DeleteEdge(2, 4);
	k->Show();

	cout <2即A<->C" << endl;
	k->DeleteEdge(2, 0);
	k->Show();

	cout << endl << "尝试插入2<->4即C<->E" << endl;
	k->InsertEdge(2, 4, 30);
	k->Show();

	cout <1即A<->A" << endl;
	k->DeleteEdge(1, 1);
	k->Show();

	cout <3即C<->D" << endl;
	k->DeleteEdge(3, 2);
	k->Show();

	cout << endl << "尝试插入2<->4即C<->E" << endl;
	k->InsertEdge(4, 2, 10);
	k->Show();

	cout << endl << "尝试修改3<->4即D<->E" << endl;
	k->ChangeEdge(3, 4, 20);
	k->Show();

	system("pause");
	return 0;
}

运行结果:

【数据结构笔记】6:无向图的邻接多重表存储结构_第1张图片
【数据结构笔记】6:无向图的邻接多重表存储结构_第2张图片

最小生成树我还没写,明天想去动物园也不知道能不能去了。

你可能感兴趣的:(数据结构)