#include<iostream>
#include<string>
using namespace std;
typedef struct node
{
int data;//数据
node* next;//连接下一个节点的指针
}node;
typedef struct Head
{
node* head;//头指针
int n;//每个集合中元素的个数
}Head;
class List
{
private:
int total;//总集合数
public:
void Input(Head a[], int n1)
{
int n;//各个集合中的元素
this->total = n1;
for (int i = 0; i < n1; ++i)
{
a[i].head = new node;
a[i].head->next = NULL;
node* last = a[i].head;
cout << "输入第" << i + 1 << "个集合的结点数" << endl;
cin >> n;
a[i].n = n;
cout << "输入元素" << endl;
for (int i = 0; i < n; ++i)
{
node* p = new node;
cin >> p->data;
last->next = p;
last = p;
}
last->next = NULL;
}
Sort(a);
}
void Output(Head a[])
{
for (int i = 0; i < total; ++i)
{
cout << "第" << i + 1 << "个集合的元素有" << a[i].n << "个,分别为" << endl;
for (node* p = a[i].head->next; p; p = p->next)
{
cout << p->data << '\t';
}
cout << endl;
}
}
//利用将该链表数据清空思想,再将数据排序插入
void Sort(Head a[])//递增排序
{
//用直接插入排序对每个集合中的元素进行排序
for (int i = 0; i < total; ++i)
{
cout << "第" << i + 1 << " 个集合 ";
node* p = a[i].head->next->next;//未排序好的结点从第二个数据开始
a[i].head->next->next = NULL;
node* q;//未排序好的结点的下一个结点
node* pre;//已排序好的结点的起点
while (p)
{
q = p->next;
pre = a[i].head;//不能直接pre=head->next,一但这样如果序好为1,0就无法排序好了
while (pre->next && pre->next->data < p->data)
pre = pre->next;
//只要遍历结束采用头插法插入
p->next = pre->next;
pre->next = p;
p = q;
}
int count = 0;//重复数
//清除重复结点
for (node* p = a[i].head, *q = a[i].head->next; q;)
{
if (p->data == q->data)//重复就删除
{
cout << p->data << " ";
//删除时不要急着p,q移动,p还是指向原来的结点,q指向下一个节点,这样有多少个重复都没事·
p->next = q->next;
delete q;
q = p->next;
--a[i].n;//该集合中的元素数目减一
++count;
}
else
{
p = p->next;
q = q->next;
}
}
if (count)cout << "重复" << count << "个" << endl;
else cout << " 无重复 " << endl;
}
//用希尔排序对每个集合中数据个数递增排序
for (int d = total / 2; d > 0; d = d / 2)
for (int i = d; i < a[i].n; i = i + 1)//未排好序的元素
{
int temp = a[i].n;//记录要排序的结点
//当碰到比temp大的就向后移,否则在碰到小的后面插入
int j = i - d;
for (; j >= 0 && a[j].n > temp; j = j - d);
a[j + d].n = temp;
}
cout << "整理结果" << endl;
Output(a);
}
void Union(Head a[], node*& L3)//L1与L2合并成L3
{
//初始化L3
L3 = new node;
L3->next = NULL;
node* last = L3;//L3尾结点
if (total == 1)//只有一个集合时直接复制
{
for (node* temp = a[0].head->next; temp; temp = temp->next)
{
node* s = new node;
s->data = temp->data;
last->next = s;
last = s;
}
last->next = NULL;
cout << total << "个元素合并结果" << endl;
for (node* p = L3->next; p; p = p->next)
cout << p->data << " ";
cout << endl;
return;
}
for (int i = 1; i < total; ++i)
{
node* p = a[i].head->next;
node* q = a[i - 1].head->next;
while (p && q)
{
if (p->data > q->data)
{
node* s = new node;
s->data = p->data;//数据复制
last->next = s;
last = s;
p = p->next;//插入后要移动
}
else if (p->data < q->data)
{
node* s = new node;
s->data = q->data;
last->next = s;
last = s;
q = q->next;//插入后要移动
}
else//此时两个相等,只插一个,然后同时移动
{
node* s = new node;
s->data = p->data;
last->next = s;
last = s;
q = q->next;
p = p->next;
}
}
//跳出循环可能只有一个为空就跳出了
//若单单p为空,那就直接利用while(q)就余下结点复制下去
//若单单q为空,可以利用q=p,用q指向p那条不空的链表,同样也可以用while(q)循环复制下去
if (p)q = p;
//复制余下结点
while (q)
{
//同样的结点复制过程
node* s = new node;
s->data = q->data;
last->next = s;
last = s;
q = q->next;
}
last->next = NULL;
}
/*合成L3链表的测试
cout << total << "个集合,合并结果" << endl;
for (node* p = L3->next; p; p = p->next)
cout << p->data << " ";
*/
//本次合并过程是第一个集合与第二个集合合并,第二个与第三个合并,但能保证相邻集合间无重复,但可能1与4集合有重复数也合并进去了
//所以还要用一个循环清除L3的重复数
//而在删去重复的时候也来个排序,过程采用清空,设新指针重新对L3进行插入
node* p = L3->next->next;//乱序的数据从第二个开始
node* q;//记录乱序q的下一个节点
L3->next->next = NULL;//重置L3链表
node* pre;//指向L3头结点
while (p)//对乱序数进行排序
{
pre = L3;
q = p->next;
while (pre->next && pre->next->data < p->data)//当pre下一个结点小于p的data,或不为空继续循环
pre = pre->next;
//跳出循环表示遍历到p的data小于pre的data或pre->next此时为空,两者都可以用头插法进行插入
p->next = pre->next;
pre->next = p;
p = q;
}
//删除重复结点
for (node* p = L3->next, *q = p->next; p && q;)
{
if (p->data == q->data)
{
p->next = q->next;
delete q;
q = p->next;
}
else
{
p = p->next;
q = q->next;
}
}
cout << total << "个集合,合并结果" << endl;
for (node* p = L3->next; p; p = p->next)
cout << p->data << " ";
cout << endl;
}
/*将元素最少的集合赋予链表L4,创建链表时已排序好,再用链表L4与各个集合求交集*/
void Insersection(Head a[], node*& L4)//交集
{
L4 = new node;
L4->next = NULL;
node* r = L4;//尾指针
node* p;//数据插入的结点
for (node* q = a[0].head->next; q; q = q->next)
{
p = new node;
p->data = q->data;
r->next = p;
r = p;
}
r->next = NULL;
//当只有一个集合时直接复制
if (total == 1) return;
//使用二路归并
for (int i = 1; i < total; ++i)
{
node* p = L4->next;//p指向L4的首结点
node* q;//q记录p所指向的下一个结点
L4->next = NULL;//L4所指的下一个结点指向空当碰到相同的在给L4插入数据
r = L4;
node* temp;//遍历比较的集合
while (p)
{
q = p->next;
for (temp = a[i].head; temp->next; temp = temp->next)
{
if (temp->next->data == p->data)//数据一样,交集插入
{
r->next = p;
r = p;
p = q;
break;
}
if (temp->next->data > p->data)//此情况表明p前的所有结点都比temp所指结点的数值都小,那p要向后移才可能找到交集
{
p = q;
break;//将p后移然后跳出循环就可
}
}
if (temp->next == NULL)break;//在p所有的元素大于temp时,不可能再有交集,直接进入下一个集合,而判断标志为temp->next==NULL
}
}
r->next = NULL;
if (L4->next == NULL) { cout << "无交集" << endl; return; }
cout << "交集结果为" << endl;
for (node* p = L4->next; p; p = p->next)
cout << p->data << " ";
cout << endl;
}
//用数据最多的集合赋予L5,再用L5删去与各集合中最小的
void Subs(Head a[], node*& L5)
{
//initialize L5(初始化L5)
L5 = new node;
L5->next = NULL;
node* r = L5;//tail pointer of L5
for (node* p = a[total - 1].head->next; p; p = p->next)
{
node* q = new node;//split new space for data creation(开辟空间用于数据创建
q->data = p->data;//data replication(数据的复制)
//data connection(数据连接)
r->next = q;
r = q;
}
r->next = NULL;
//if there is only one set,copy the data of set directly to the linked list
//(集合只有一个那就将直接将集合里的数据复制给链表)
if (total == 1);
else
{
//with two-way merge method,reset L5 evert time ,find the match and connect
//用二路归并法,每次都重置L5,找到符合的再连接起来
for (int i = total - 2; i>=0; --i)
{
node* p = L5->next;
node* q;//record the next node of p(记录p的下一个结点)
L5->next = NULL;
r = L5;//don't forget to reset the tail node(别忘了重置尾结点)
while(p)
{
q = p->next;
node* temp=a[i].head->next;//pointer to iterate through the ith set(遍历第i个集合的指针)
//when the value of temp if small,temp alaways move backward
//当temp的数据比p小,temp就一直往后移
for (; temp && p->data > temp->data; temp = temp->next);
if(!(temp!=NULL&&temp->data==p->data))
{
r->next = p;
r = p;
}
p = q;
}
r->next = NULL;
}
}
if (L5->next == NULL)
{
cout << "作差为空" << endl;
return;
}
cout << "最后一个元素与其他元素做差的结果";
for (node* p = L5->next; p; p = p->next)
cout << p->data << " ";
cout << endl;
}
};
int main()
{
List list;
Head* L;
node* L3;//并集头结点
node* L4;//交集头结点
node* L5;//差集头结点
int n;
cout << "输入你要创建的集合数" << endl;
cin >> n;
L = new Head[n];
list.Input(L, n);
list.Union(L, L3);
list.Insersection(L, L4);
list.Subs(L, L5);
return 0;
}
数据结构,多个集合的交并差运算
最新推荐文章于 2023-11-21 13:40:18 发布