1. 程式人生 > >C++刷題記錄之:集合union

C++刷題記錄之:集合union

前言

好久沒有寫C語言的題目了,畢竟現在在學習資料結構,還是要練習c++的,上課的時候老師提到一個萬能標頭檔案#include<bits/stdc++.h>

今天在一個平臺練習C語言的時候正好使用這個檔案頭,感覺挺輕鬆的,省去很多標頭檔案,接下來對題目進行簡單的分析。

題目描述:集合union

                                             圖一:題目

題目描述

假設利用兩個線性表LA和LB分別表示兩個集合A和B(即:線性表中的資料元素即為集合中的成員),現要求一個新的集合A=A∪B。這就要求對線性表

做如下操作:擴大線性表LA,將存在於線性表LB中而不存在於線性表LA中的資料元素插入到線性表LA中去。只要從線性表LB中依次取得每個元素,

並依值線上性表LA中進行查訪,若不存在,則插入之。上述操作過程可用下列演算法描述之。

                             圖二:將兩個列表合併的演算法(C/C++描述)

上圖演算法中,在第8行取得集合B中的元素,然後再在第10行插入到集合A中。你的任務是先輸出集合A和集合B中的元素,每個集合在一行中輸出。

然後每次在將集合B中的元素取出插入到集合A尾部後輸出集合A中的元素。當然你的程式碼可以和上面的程式碼不一樣,只要有相同的輸出即可。

輸入

有多組測試資料,每組測試資料佔兩行。第一行是集合A,第一個整數m(0<m<=100)代表集合A起始有m個元素,後面有m個整數,代表A中的元素。

第二行是集合B,第一個整數n(0<n<=100)代表集合B起始有n個元素,後面有n個整數,代表B中的元素。每行中整數之間用一個空格隔開。

輸出

每組測試資料輸出n+2行:前兩行分別輸出集合A、集合B中的資料,後面n行是每次從B中取出元素插入到A尾部後的集合A。

每行整數之間用一個空格隔開,每組測試資料之間用一行空行隔開。

                 圖三:題目運算時的輸入

提示

提示:

1、使用陣列時,給集合 A 分配的空間不小於200。因為將 B 中的元素新增到 A 中時,可能會超過 100 了。

2、利用 scanf("%d",&m) != EOF 來判斷是否還有輸入資料。

3、一個細節問題就是題目要求輸出的格式是每行中元素之間用一個空格隔開,每組輸出間用一個空行隔開。也就是說4個元素間只有3個空格,

2組輸出間只有1個空行。處理方法都一樣。兩種方法:一是除了第一個元素,後面的每個元素之前輸出個空格;二是除了最後一個元素,

前面的每個元素之後都輸出一個空格。我往往採用第一種方式,因為許多程式語言中的陣列都是從0開始的,

而0正是判斷語句中的“假”(當然Java中不是這樣的)。

總結:

本題考查的是線性表的基本操作。實際上只考察了遍歷和新增操作。雖然演算法中使用的是“插入”,然而本題只要求插入到連結串列的尾部,

因而只是新增而已。線性表按儲存結構分為順序表和連結串列。順序表在插入時往往需要移動某些元素,而移動元素需要消耗大量時間。

如果插入操作次數很多的話,採用連結串列會好些。但由於只是插入到線性表的尾部,因而也不必移動元素。

所以採用順序表解本題也不失為一個好方法。如果採用順序表,事先需要分配足夠的記憶體。題目中 m 和 n 都是不大於100的,

是不是給兩個順序表(陣列實現)分配100的記憶體就夠了呢?答案是否定的。因為將集合 B 新增到集合 A 中很可能就超過100個元素了。

還有,題目沒有給定多少組測試資料,我們的方法就是判斷是否讀到了檔案結尾。利用 scanf("%d",&m) != EOF 來作判斷即可。

對於解本題的演算法,題目描述中已經有了,我就不再贅述。除了基本操作以外,還要看怎麼輸出。

實際上就是在每次插入後使用一個迴圈將集合 A 中的所有元素輸出即可。

題目分析

①:輸入兩個集合LA,LB

②:求它們的並集

1):遍歷LB中的所有元素,看是否存在於LA中

2):若存在則把該元素插入到LA的末尾,並輸出LA,換行

3):若不存在,則也輸出LA,換行

③:一組資料結束後,換行

注意事項:

1)根據上面求並集過程,LA的輸出次數與LB的元素個數有關

即:LB中有n個元素,求並集過程時LA得輸出n次,若n=0則不輸出

2)題目要求輸入集合後,要輸出該集合,若集合長度為0,也不輸出

3)每次輸出佔一行

4)每組資料輸出完後,空一行

如:

LA :1 1

LB:0

①先輸出LA元素1換行;②LB沒有元素,不輸出;③又因為LB長度為0,所以之後的LA輸出次數為0;④最後換行

LA:0

LB:0

①:首先,LA沒有元素,不輸出;②然後LB沒有元素,不輸出;③又因為LB長度為0,所以之後的LA輸出次數為0;④最後換行

LA:0

LB:1 1

①首先,LA沒有元素,不輸出;②然後輸出LB元素1換行;③LB長度為1輸出一次LA換行,④最後換行

參考程式碼

#include<bits/stdc++.h>
typedef struct Union_{
 
   int *elem;
   int length;
   int size_;
 
}*Union,UNION;
 
void creat_union(Union L);
void combin_(Union LA,Union LB);
void out_put(Union L);
 
int main()
{
 
UNION LA,LB;
 
while(scanf("%d",&LA.size_)!=EOF)
  {
  creat_union(&LA);
/*輸入LB的長度*/
  scanf("%d",&LB.size_);
  creat_union(&LB);
/*合併兩個集合*/
  if(LA.size_!=0||LB.size_!=0)
  combin_(&LA,&LB);
  /*每組資料輸出後用一行隔開*/
  printf("\n");
 
 
  }
return 0;
}
/*------------------------------------------------*/
void creat_union(Union L)
{
 
L->elem=(int *)malloc(L->size_*sizeof(int));
L->length=0;
 
  for(int i=0;i<L->size_;i++)
{scanf("%d",&L->elem[i]);L->length++;}
/*長度不是0時才輸出*/
if(L->length!=0)
out_put(L);
}
/*------------------------------------------------*/
void combin_(Union LA,Union LB)
{
 
int j;
/*為了避免每次插入都要分配,導致分配次數過多,所以直接給LA->elem[],重分配空間大小為
LA->length+LB->length,但這種分配可能會造成空間浪費,還有一種方法是把要插入的元素個數求出來,再分配
但浪費時間*/
 if(LA->length+LB->length>LA->size_)
LA->elem=(int *)realloc(LA->elem,(LA->length+LB->length)*sizeof(int));
 
for(int i=0;i<LB->length;i++)
  {
  /*判斷LB中下標為i的元素在LA中是否存在*/
for(j=0;j<LA->length;j++)
{
   if(LA->elem[j]==LB->elem[i])
   break;
}
 /*若果不存在則把LB->elem[i]插入到LA末尾,再插入之前,先重分配空間*/
   if(j==LA->length)
 {
LA->elem[LA->length++]=LB->elem[i];
 
 }
 out_put(LA);
 
  }
 
}
/*------------------------------------------------*/
void out_put(Union L)
{ /*除最後一個元素外,其餘元素輸出後都有空格*/
 
   for(int i=0;i<L->length-1;i++)
printf("%d ",L->elem[i]);
/*輸出最後一個元素*/
  printf("%d\n",L->elem[L->length-1]);
 
}

需要注意的是:該標頭檔案#include<bits/stdc++.h>為C++語言所使用的,所以在提交的時候需要選擇使用C++語言