您的位置:首页 > 理论基础 > 数据结构算法

重学数据结构系列之——图的储存

2016-04-09 11:41 501 查看

1.什么是图

比如说我们的关系网络,就来微信来说,我们把用户看成是一个点,是好友的我们就把这两个点连起来。
如下面的就是一个简单的图



2.图的分类

有向图和无向图,上图就是无向图,有向图是单向的,边用箭头来表示,如下:



3.图的常用概念

顶点:就是那些点咯
边:就是连接两个顶点的线,分为有向边和无线边

下面一般是指有向图
入度:该顶点有多少个箭头指着
出度:该顶点有多少条边箭头指着别人
顶点的度为入度与出度之和

3.图一般的储存方式

邻接矩阵和邻接表

4.邻接矩阵储存的实现

其实就是用一个二维数组来储存,比如说是二维数组mat,mat[1][2]=1 ,就说明编号为1,2的两个顶点有边(这里编号从0开始)
#include <iostream>
#include <cstring>
using namespace std;

class Graph{
private:
int **mat;	//邻接矩阵,其实就是二维数组
int n;	//顶点个数
public:
Graph(int input_n){
n= input_n;
//先分配n个int*的指针,再对每个指针再循环分配
mat = new int*
;
for (int i = 0; i < n; i++) {
mat[i] = new int
;
//将内存中mat[i]的sizeof(int)*n个字节的内容全部设置为那个字符的ASCII值(这里的字符好似0)
//它是对较大的结构体或数组进行清零操作的一种最快方法
memset(mat[i], 0, sizeof(int)*n);//Sets buffers to a specified character.
}
}
~Graph(){
//析构时注意先析构里面的,再外层的
for (int i = 0; i < n; i++) {
delete[] mat[i];
}
delete[] mat;
}
//插入边,直接将对于的位置置为1就可以了
void insert(int x, int y){
mat[x][y] = 1;
}
//输出邻接矩阵
void output(){
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout<<mat[i][j]<<" ";
}
cout<<endl;
}
}
};

int main(){
//n:顶点个数	m:有向边个数
//x,y: 表示插入一条x连向y的有向边
int n, m, x, y;
cin >> n >> m;
Graph g(n);
for (int i = 0; i< m; i++) {
cin >> x >> y;
g.insert(x, y);
}
g.output();
return 0;
}


对memset的理解: 通过调试,可以看到内存的地址的值全都变成了00000000,因为int是四个字节嘛,那int指针也是。



运行结果:



5.邻接表的储存实现

#include <iostream>
using namespace std;

//链表结点
class LinkedListNode{
public:
//vertex:链表结点的值
int vertex;
//指向下一个结点的指针
LinkedListNode *next;
LinkedListNode(int vertex_input){
vertex = vertex_input;
next = NULL;
}
};

//链表
class LinkedList{
public:
LinkedListNode *head;

LinkedList(){
head = NULL;
}

~LinkedList(){
//顺着链析构
while (head != NULL) {
LinkedListNode *delete_node = head;
head = head->next;
delete delete_node;
}
}
//插入函数,这里直接插到头的前面了
void insert(int vertex){
LinkedListNode *node = new LinkedListNode(vertex);
node->next = head;
head = node;
}
};

//图
class Graph{
private:
//储存链表的指针
LinkedList *edges;
//n:顶点数目
int n;
public:
Graph(int input_n){
n = input_n;
edges = new LinkedList
;
}
~Graph(){
delete[] edges;
}

//插入就调用链表的插入
void insert(int x, int y) {
edges[x].insert(y);
}

//循环输出每个链表的每个结点的值即可
void output() {
for (int i = 0; i < n; i++) {
cout<<i<<":";
//auto 是 C++11 的新特性,在定义变量时无需指定类型,编译器会通过类型推导得到实际的类型
//但我用vc++6.0,所以不支持
//for (auto* j = edges[i].head; j != NULL; j = j->next) {
for (LinkedListNode* j = edges[i].head; j != NULL; j = j->next) {
cout<<j->vertex<<" ";
}
cout<<endl;
}
}
};

int main(){
int n, m, x, y;
cin >> n >> m;
Graph g(n);
for (int i = 0; i < m; ++i) {
cin >> x >> y;
g.insert(x, y);
}
g.output();
return 0;
}


运行结果:(可以看到结果非常直观,那个顶点有没有指向谁的边都一眼看出来)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: