一个不相交数据结构维护了一个不相交动态集的集合S = {S1, S2,,,,,Sn},用一个代表来标示每个集合,这个代表是集合中的任意一个元素。
支持一下三种操作:
1、MakeSet(x):建立一个新的集合,成员为x,因为各个集合是不相交的,故不出现在任何其他集合中。
2、Uinon(x, y):将包含x和y的两个集合合并成一个新的集合,即为这两个集合的并集。
3、FindSet(x):返回一个指针,这个指针指向包含x的集合的代表。
一个实现不相交集合的数据结构是链表表示:每个集合用一个自己的链表来表示,每个集合的对象包含head属性和tail属性,head属性指向标的第一个对象,tail属性指向标的最后一个对象。集合的代表是链表中第一个对象的集合对象。
书上写的findset仅需要沿着x对象的返回指针返回到集合对象,然后返回head指向对象的成员,难道他的x指的是这个结点的指针吗?哎,我给出的是节点值,得遍历链表找,花销为O(n)...因为找到这个节点要遍历整个集合.....
union是将含有少的结点的集合连接到大的集合中,在每个集合的链表的头结点中记录该集合的个数。
但是为了保持数据一致性,我写的这个实际上data只能是int,才能在头结点中使用记录个数的整数T_T,还是写的很差啊,哎
谁知道到底应该怎么写的?
下面是我的。。。
表示的集合是相当于书上算法导论第三ban326页的集合
#include <iostream>
#include <vector>
//#include <crtdbg.h>
using namespace std;
template <typename DataType>
struct LinkNode
{
DataType data; //如果是集合的根,则存储的是集合的大小,否则为数据
LinkNode *head;
LinkNode *tail;
LinkNode() : head(NULL), tail(NULL) {}
};
template <typename DataType>
class DisjLinkSet
{
public:
typedef LinkNode<DataType> LNode;
DisjLinkSet(int n) : num(n)
{
//初始化向量,存储每个链表的头结点
for (int i = 0; i < n; i++)
{
LNode lnode;
lnode.data = 0;
lnvec.push_back(lnode);
}
}
//使val成为一个单独的集合
void makeSet(DataType val)
{
LNode *node = new LinkNode<DataType>;
node->data = val;
node->head = &lnvec[i];
node->tail = NULL;
lnvec[i].head = node;
lnvec[i].tail = node;
lnvec[i].data++;
i++;
}
//找到val所在的集合,并且返回集合的头结点
LNode *findSet(DataType val)
{
for (int i = 0; i < num; i++)
{
if (lnvec[i].head != &(lnvec[i]))
{
LNode *node = lnvec[i].head;
if (node->data == val)
return node->head;
}
}
return NULL;
}
//将较短的表接在较长的表中, 输入为两个元素,
//输出为较长表的表头结点的head结点的元素值
DataType unionSet(DataType vx, DataType vy)
{
LNode *x = findSet(vx);
LNode *y = findSet(vy);
if (x == NULL | y == NULL)
return NULL;
//y所在链表的长度小于等于x
if (y->data <= x->data)
{
//将x所在链表的最后一个结点的tail指向y指向的链表
x->tail->tail = y->head;
//将x所在链表的表头指针的tail指向y所在链表的表头指针的tail
x->tail = y->tail;
//依次将y所在链表的每个结点的head指向x
LNode *node = y->head;
while (node != NULL)
{
node->head = x;
node = node->tail;
}
x->data += y->data;
//将y所在链表的表头清空
y->head = y;
y->tail = y;
y->data = 0;
return x->head->data;
}
else
{
//将y所在链表的最后一个结点的tail指向x指向的链表
y->tail->tail = x->head;
//将y所在链表的表头指针的tail指向x所在链表的表头指针的tail
y->tail = x->tail;
//依次将x所在链表的每个结点的head指向y
LNode *node = x->head;
while (node != NULL)
{
node->head = y;
node = node->tail;
}
y->data += x->data;
//将x所在链表的表头清空
x->head = x;
x->tail = x;
x->data = 0;
return y->head->data;
}
}
//显示各个集合的元素
void display()
{
for (int i = 0; i < num; i++)
{
if (lnvec[i].data == 0)
cout << "第 " << i+1 << " 个集合没有元素";
else
{
cout << "第 " << i+1 << " 个集合有" << lnvec[i].data
<< "个元素, 分别是:";
LNode *node = lnvec[i].head;
while (node->tail != NULL)
{
cout << node->data << " ";
node = node->tail;
}
cout << node->data << " ";
}
cout << endl;
}
cout << "*******************************" << endl;
}
//删除各个集合的元素
void destory()
{
for (int i = 0; i < num; i++)
{
if (lnvec[i].data != 0)
{
LNode *node = lnvec[i].head;
while (node->tail != NULL)
{
lnvec[i].head = node->tail;
delete node;
node = NULL;
node = lnvec[i].head;
}
delete node;
node = NULL;
}
}
}
private:
int num; //总共有的元素个数
vector<LNode> lnvec; //存放集合的头结点
static int i; //使每个结点成为单独集合时使用的数组序号
};
int DisjLinkSet<int>::i = 0;
int main()
{
DisjLinkSet<int> dj(7);
dj.makeSet(6);
dj.makeSet(7);
dj.makeSet(4);
dj.makeSet(3);
dj.makeSet(8);
dj.makeSet(5);
dj.makeSet(2);
int d1 = dj.unionSet(6, 7);
dj.display();
int d2 = dj.unionSet(d1, 4);
dj.display();
int d3 = dj.unionSet(3, 8);
dj.display();
int d4 = dj.unionSet(5, 2);
dj.display();
int d5 = dj.unionSet(d3, d4);
dj.display();
int d6 = dj.unionSet(d2, d5);
dj.display();
dj.destory();
/* _CrtDumpMemoryLeaks();*/
system("pause");
return 0;
}
运行结果为: