图也是一种 非线性结构,是由多个顶点组成的关系集合组成的一种数据结构。图可以分为两种,无向图和有向图。
★图的定义:
★典型问题:
利用图能够解决很多问题,这里有一个较为典型的问题,假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或者间接的好友(即就是好友的好友...),则认为他们属于一个朋友圈,请写出程序求出这n个人里一共有多少个朋友圈。
例如:n = 5, m = 3, r = {{1,2},{2,3},{4,5}}, 表示有5个人,1和2是朋友,2和3也是朋友,4和5是朋友,则1,2,3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。
★解题思路:
首先,先介绍一个概念:并查集。并查集就是将N个不同元素分成一组不想交的集合,开始时,每个元素就是一个集合,然后按规律将两个集合进行合并。具体的做法如下:
设定一个有N个元素的数组,将每个元素对应的位置都置为-1,即就是先让其没有相交,然后根据题目中给出的朋友关系,将根节点元素对应的位置减1,将与根节点是好友的元素对应的位置更改为根节点元素,按照这样的方式,将所有的关系都进行对应,最后数组中如果是负数,所对应的元素就是根节点。
★具体代码:
#pragma once #include <assert.h> //实现图 ——并查集 /* 主要功能:给定一个范围,能够确定朋友圈的个数 */ class UnionFindSet { public: UnionFindSet(size_t size) //构造函数 :_n(size) , _set(new int[size]) { for (int i = 0; i < size; i++) //将_set中的数据最先初始化为-1 { _set[i] = -1; } } void Union(int root1, int root2) //结合两个根节点 { assert(_set[root1] < 0); assert(_set[root2] < 0); _set[root1] += _set[root2]; _set[root2] = root1; } size_t FindRoot(int child) { if (_set[child] < 0) //负数证明这个节点就是根节点 { return child; } int num = _set[child]; while (num >= 0) { num = _set[num]; } return num; } void print() { int root = 0; for (int i = 0; i < _n; i++) { if (_set[i] < 0) { root++; } } cout << "输出有几个朋友圈:" << root << endl; } protected: int* _set; //数组指针 size_t _n; //给定范围数据的个数 }; void Test() { UnionFindSet ht(10); ht.Union(0, 6); ht.Union(0, 7); ht.Union(0, 8); ht.Union(1, 4); ht.Union(1, 9); ht.Union(2, 3); ht.Union(2, 5); ht.print(); }