Pers.narod.ru. Алгоритмы. Объединение, пересечение и разность множеств, реализация через массивы

Объединением множеств A и B называется множество элементов, принадлежащих, по крайней мере, одному из данных множеств (т. е. либо A, либо B, либо одновременно и A и B). Эту операцию обозначают A∪B и читают "объединение A и B".

Пересечением множеств A и B называется множество элементов, принадлежащих одновременно и A и B. Обозначают A∩B и читают "пересечение A и B".

Разностью множеств A и B называется множество элементов, принадлежащих A и не принадлежащих B. Обозначают A\B и читают "разность A и B".

Прилагаемая ниже программа реализует множества как статические массивы языка Си и содержит функции для выполнения указанных операций над массивами. Функции возвращают указатели на новый массив, который формируется динамически и является результатом операции. Предварительно из массивов удаляются одинаковые элементы, если они там есть.

#include <stdio.h>
#include <alloc.h>

void delete_equal (int *n0, int *a) {
 //Удаляет из массива повторяющиеся элементы и вычисляет новую размерность n0
 int n=*n0;
 int i=0;
 while (i<n) {
  int j=i+1;
  while (j<n) {
   if (a[i]==a[j]) {
    for (int k=j; k<n-1; k++) a[k]=a[k+1];
    n--;
   }
   else j++;
  }
  i++;
 }
 *n0=n;
}

int find_item(int na,int *a,int b) {
 //Ищет элемент b в массиве a[na] и возвращает его индекс или -1 (не найдено)
 for (int i=0; i<na; i++) if (a[i]==b) return i;
 return -1;
}

int *copy_array (int n, int *a, int *c) {
 //Копирует массив a в новый массив c и возвращает указатель на него
 c=(int *)calloc (n,sizeof(int));
 if (c==NULL) return NULL;
 for (int i=0; i<n; i++) c[i]=a[i];
 return &c[0];
}

int *union_array (int na, int *a, int nb, int *b, int *nc) {
 //Объединение массивов a и b с размерностями na и nb
 //в новый динамический массив (в массив войдут уникальные элементы,
 //присутствующие хотя бы в одном из массивов a,b)
 int *c,i,j;
 if (na<1) {
  if (nb<1) return NULL;
  else {
   delete_equal (&nb,b);
   return copy_array (nb,b,c);
  }
 }
 else if (nb<1) {
  delete_equal (&na,a);
  return copy_array (na,a,c);
 }
 delete_equal(&na,a);
 delete_equal(&nb,b);
 //Вычисляем количество разных элементов в 2 массивах
 int kc=0;
 for (i=0; i<na; i++) if (find_item(nb,b,a[i])!=-1) kc++;
 *nc=na+nb-kc;
 c=(int *)calloc (*nc,sizeof(int));
 if (c==NULL) return NULL;
 //Формируем массив c
 int k=0;
 for (i=0; i<na; i++) c[k++]=a[i];
 for (j=0; j<nb; j++) if (find_item(na,a,b[j])==-1) c[k++]=b[j];
 return c;
}

int *cross_array (int na, int *a, int nb, int *b, int *nc) {
 //Пересечение массивов a и b с размерностями na и nb
 //в новый динамический массив (в массив войдут уникальные элементы,
 //присутствующие в каждом из массивов a,b)
 int *c,i,j;
 if (na<1 || nb<1) return NULL;
 delete_equal(&na,a);
 delete_equal(&nb,b);
 //Вычисляем количество одинаковых элементов в 2 массивах
 *nc=0;
 for (i=0; i<na; i++) if (find_item(nb,b,a[i])!=-1) (*nc)++;
 c=(int *)calloc (*nc,sizeof(int));
 if (c==NULL) return NULL;
 //Формируем массив c
 int k=0;
 for (i=0; i<na; i++) if (find_item(nb,b,a[i])!=-1 && find_item(k,c,a[i])==-1) c[k++]=a[i];
 for (j=0; j<nb; j++) if (find_item(na,a,b[j])!=-1 && find_item(k,c,b[j])==-1) c[k++]=b[j];
 return c;
}

int *diff_array (int na, int *a, int nb, int *b, int *nc) {
 //Разность массивов a и b с размерностями na и nb
 //в новый динамический массив (в массив войдут уникальные элементы,
 //присутствующие в массиве a, но отсутствующие в b)
 int *c,i,j;
 if (na<1) return NULL;
 delete_equal(&na,a);
 if (nb<1) return copy_array (na,a,c);
 delete_equal(&nb,b);
 //Вычисляем количество элементов в массиве a, отсутствующих в b
 *nc=0;
 for (i=0; i<na; i++) {
  int kc=0;
  if (find_item(nb,b,a[i])!=-1) kc++;
  if (kc==0) (*nc)++;
 }
 c=(int *)calloc (*nc,sizeof(int));
 if (c==NULL) return NULL;
 //Формируем массив c
 int k=0;
 for (i=0; i<na; i++) if (find_item(nb,b,a[i])==-1) c[k++]=a[i];
 return c;
}

void print_array (int n,int *a) { //Выводит массив на экран
 printf ("\n");
 for (int i=0; i<n; i++) printf ("%5d ",a[i]);
}

void wait() { //Ждет нажатия клавиши
 printf ("\nPress a key to continue...");
 fflush (stdin); getchar();
}

const int na=6, nb=5; //Размерности массивов a,b
int a[na] = { 4, 4, 2, 5, 3, -1 },
    b[nb] = { 2, 3, 4, 4, 1};
    //Описали множества как массивы

void main () {
 int nc;
 printf ("\na=");
 print_array (na,a);
 printf ("\nb=");
 print_array (nb,b);
 printf ("\nUnion (a,b)=");
 int *c=union_array (na,a,nb,b,&nc);
 print_array (nc,c);
 int nd;
 printf ("\nCross (a,b)=");
 int *d=cross_array (na,a,nb,b,&nd);
 print_array (nd,d);
 int ne;
 printf ("\nDifference (a,b)=");
 int *e=diff_array (na,a,nb,b,&ne);
 print_array (ne,e);
 wait();
}

То же самое через множества на Паскале

На Паскале всё гораздо проще и человечней - тип множества (set) включён в язык. Правда, входить в множество могут только величины типа byte со значениями от 0 до 255 включительно, так что нашу -1 в множестве A заменим на 11. Зато Паскаль автоматически исключает из множеств одинаковые элементы, поэтому соответствующую обработку писать не нужно.

Таким образом, вся предыдущая программа может быть сведена к следующему:

type range = set of byte;
var a,b : range;

procedure writeset (name:string;a:range);
var i:byte;
begin
 write (name,' ');
 for i:=0 to 255 do if i in a then write (ord(i),' ');
 writeln;
end;

begin
 a := [4,4,2,5,3,11];
 b := [2,3,4,4,1];
 writeset ('a',a);
 writeset ('b',b);
 writeset ('a+b',a+b);
 writeset ('a*b',a*b);
 writeset ('a\b',a-b);
 writeln ('Press Enter...');
 readln;
end.

Рейтинг@Mail.ru

вверх гостевая; E-mail
Hosted by uCoz