Структури от данни
Н. Киров

"Алгоритми + структури от данни = програми"
                                                                  Н. Вирт

1. Масиви - задачи за симулации с подхвърляне на монета и изчисляване на най-близки точки
2. Свързани списъци - задача на Йосиф, обръщане на свързан списък, намиране на n-ти най-малък елемент
3. Съставни структури от данни - двумерен масив. Сортиране на масив от низове



Ефективно използване на масив - разултатът от изчислението като индекс на масив.
Симулация на Бернулиеви опити: подхвърляме монета N пъти, вероятността да видим k езита е "N над k по 1/2^N" - нормално разпределение. Да напишем програма, която прави M такива опити (всеки опит по N подхвърляния) и чертае хистограма на получените резултати - брой на получените езита (10 опита е 1 *).

// bern.cpp
#include <iostream>
#include <cstdlib>
#include <iomanip>
using namespace std;

bool heads()
{ return rand() < RAND_MAX/2; }

int main(int argc, char *argv[])
{
 int N = atoi(argv[1]), M = atoi(argv[2]);
 int *f = new int[N+1];
 for (int j = 0; j <= N; j++) f[j] = 0;
 int cnt, j;
 for (int i = 0; i < M; i++, f[cnt]++)
   for (cnt = 0, j = 0; j <= N; j++) if (heads()) cnt++;
 for (j = 0; j <= N; j++)
 {
  cout << setw(2) << j;
  for (int i = 0; i < f[j]; i+=10) cout << "*";
  cout << "\n";
 }
 cin.get();
 return 0;
}

bern 25 2000

*Напишете програма, която определя емпирично броя на случайни положителни цели числа, по-малки от 1000, които си генерират преди да се получи повтаряща се стойност.



Масиви от структури
Най-близки точки: генерираме случайно N точки в единичния квадрат е намираме броя на двойките точки, които са на разстояние по-малко от d.

// npoints.cpp
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;

struct Point {
  double x;
  double y;
};

double distance(Point a, Point b)
{
 double dx = a.x - b.x, dy = a.y - b.y;
 return sqrt(dx*dx + dy*dy);
}

double randFloat()
{ return 1.0*rand()/RAND_MAX;  }

int main(int argc, char *argv[])
{
 int  N = atoi(argv[1]);
 double d = atof(argv[2]);

 Point *a = new Point[N];
 for (int i = 0; i < N; i++)
 { a[i].x = randFloat(); a[i].y = randFloat(); }

 int cnt = 0;
 for (int i = 0; i < N; i++)
  for (int j = i+1; j < N; j++)
   if (distance(a[i], a[j]) < d) cnt++;

 cout << cnt <<" edges shorter than " << d << "\n";
 cin.get();
 return 0;
}

npoints 100 0.5

Квадратична сложност !!

*Модифицирайте програмата така, че да отпечати координатите на двете най-близки точки.



Използване на свързани списъци - кръгов (цикличен) списък
Нека N човека са подредени в кръг. За избиране на лидер се използва елиминиране на всеки M-ти от кръга (подобно на детска игра ). Избраният лидер е стойност на функция с аргументи N и M - функция на Йосиф.

// josif.cpp
#include <iostream>
#include <cstdlib>
using namespace std;

struct Node
{
 int item;
 Node* next;
};

int main(int argc, char *argv[])
{
 int N = atoi(argv[1]), M = atoi(argv[2]);
 Node *t = new Node,  *x = t;
 t->item = 1; t->next = t;
 for (int i = 2; i <= N; i++)
 {
  x = (x->next = new Node);
  x->item = i; x->next = t;
 }
 while (x != x->next)
 {
  for (int i = 1; i < M; i++) x = x->next;
  cout << x->next->item << "\n";
  x->next = x->next->next; N--;
  cout << x->item << "\n";
 }
 cin.get();
 return 0;
}

josif 9 5
дава резултат 517436928

*Намерете стойността на функцията на Йосиф за N = 2, 3, 5, 10 и M= 10E3, 10E4, 10E5, 10E6.



Обработка на свързани списъци
Обръщане на свързан списък:
Node* reverse(Node* x)
{
 Node *t, *y = x, *r = NULL;
 while (y != NULL)
 {
  t = y->next; y->next = r;
  r = y; y = t;
 }
 return r;
}

*Модифицирайте програмата за пресмятане на функцията на Йосиф така, че елиминирането да става в посока, обратна на номерацията на елементите.
*Напишете функция, която премества най-големия елемент в даден списък така, че да стане последен в списъка.



Ефективна реализация на "трудна" задача за свързан списък
Намиране на m-тия преди последния елемент на свързан списък

#include <iostream>
using namespace std;

struct Node
{
 int item;
 Node* next;
};

int main()
{
 int N = 10, m=1;
 Node* top = new Node,  *x = top;
 top->item = 1; top->next = NULL;
 for (int i = 2; i <= N; i++)
 {
  x = (x->next = new Node);
  x->item = i; x->next = NULL;
 }
 x = top;
 for (int i=0; i<m; i++)
 {
  if (x->next) x = x->next;
  else return 1;
 }
 Node* mx = top;
 while (x->next)
 {
  x = x->next;   mx = mx -> next;
 }
 cout << mx->item << "\n";
 cin.get();
 return 0;
}
* Даден е свързан списък, който е или цикличен или ацикличен. Да се напише функция, която определя от кой вид е списъка.



Сортиране на масив от низове.
Въвеждаме низове от стандартния вход , сортираме ги и ги извеждаме на стандартния изход - по един низ на ред.

#include <iostream>
#include <cstdlib>
#define Nmax 1000
#define Mmax 10000
using std::cin; using std::cout;

char buf[Mmax];
int M = 0;

const int compare(const void *i, const void *j)
{
 return strcmp(*(char **)i, *(char **)j);
}

int main()
{
 int N;
 char* a[Nmax];
 for (N = 0; N < Nmax; N++)
 {
  a[N] = &buf[M];
  if (cin >> a[N]) M += strlen(a[N])+1;
 }
 qsort(a, N, sizeof(char*), compare);
 for (int i = 0; i < N; i++) cout << a[i] << "\n";
 cin.clear(); cin.get();
 return 0;
}

*Модифицирайте програмата да обработва входни низове индивидуално (отделя памет за всеки низ след прочитането му от входа). Сравнете бързодействието на двете програми.