§ 18. Сартаванне аднамернага масіву

18.6. Выкарыстанне функцыі параўнання

Усе сартаванні, разабраныя вышэй, дазвалялі ўпарадкаваць элементы масіву па ўзрастанні. Калі ў алгарытме замяніць параўнанне элементаў на параўнанне значэнняў функцыі ад гэтых элементаў, то сартаванні могуць быць разнастайнымі.

Функцыю для параўнання двух аб’ектаў называюць кампаратарам (ад англ. compare — параўнаць).

Функцыя-кампаратар залежыць ад двух параметраў і вяртае лагічнае значэнне. Тып параметраў функцыі павінен супадаць з тыпам элементаў у масіве. Функцыя павінна вяртаць значэнне true для двух значэнняў, якія знаходзяцца «ў парадку», і false ў адваротным выпадку.

Прыклад 18.17. Дадзены лінейны масіў з цэлых лікаў. Напісаць праграму сартавання масіву так, каб усе цотныя лікі стаялі ў пачатку масіву, а няцотныя — у канцы. Даныя згенерыраваць выпадковым чынам.

Этапы выканання задання

I. Зыходныя даныя: пераменныя n — колькасць лікаў у масіве, a — масіў.

II.  Вынік: адсартаваны масіў а.

III. Алгарытм рашэння задачы.

  1. Увод зыходных даных. Элементы масіву згенерыраваны выпадковым чынам.
  2. Для рашэння задачы будзем выкарыстоўваць алгарытм сартавання абменам.
  3. Створым кампаратар (функцыю параўнання), якая будзе параўноўваць лікі па астачах ад дзялення на 2.
  4. Будзем мяняць элементы месцамі, калі яны размешчаны «не ў парадку».
  5. Вывад выніку.

IV. Апісанне пераменных: n – int, a –  vector<int>.

Для рашэння гэтай задачы выбар алгарытму сартавання абменам не з’яўляецца аптымальным, паколькі ён патрабуе каля n2 аперацый параўнання і абмену. Прыклад неабходны для таго, каб паказаць выкарыстанне функцыі-кампаратара.

Для атрымання аптымальнага рашэння можна зыходзіць з таго факта, што ўсе лікі адносна астачы пры дзяленні на 2 бываюць усяго дзвюх катэгорый (цотныя і няцотныя), і для іх сартавання дастаткова усяго аднаго праходу па масіве. Гэта можна зрабіць па аналогіі з алгарытмам хуткага сартавання з дапамогай двух паказальнікаў: злева шукаем першы няцотны, а справа — апошні цотны і мяняем іх месцамі (прыклад 18.18).

Прыклад 18.19. Дадзены лінейны масіў са слоў. Напісаць праграму сартавання масіву так, каб словы размяшчаліся ў парадку спадання колькасці літар «а» ў слове. Даныя прачытаць з файла.

Этапы выканання задання

I. Зыходныя даныя: пераменныя n — колькасць слоў у масіве, a — масіў.

II. Вынік: адсартаваны масіў  а.

III. Алгарытм рашэння задачы.

  1. Увод зыходных даных.
  2. Для рашэння задачы будзем выкарыстоўваць алгарытм сартавання выбарам.
  3. Створым кампаратар (функцыю параўнання), які будзе параўноўваць словы па колькасці літар «а» ў слове.
  4. Таксама створым функцыю, якая будзе вызначаць колькасць літар «а» ў слове.
  5. Вывад выніку.

IV. Апісанне пераменных: n – int, a –  vector<string>.

Прыклад 18.20. У тэкставым файле input.txt захоўваецца інфармацыя пра студэнтаў. Для кожнага студэнта паказаны яго прозвішча, горад, з якога ён прыехаў, і тры лікі — балы за ЦТ, з якімі ён паступіў у ВНУ. Адсартаваць спіс студэнтаў у парадку спадання сумарнага бала за ЦТ. Вывесці прозвішча, горад і сумарны бал.

Этапы выканання задання

 I. Зыходныя даныя: пераменныя n — колькасць запісаў пра студэнтаў, a — масіў структур.

 II. Вынік: адсартаваны масіў а.

III. Алгарытм рашэння задачы.

  1. Увод зыходных даных.
  2. У апісанні структуры, акрамя палёў, паказаных ва ўмове задачы, дабавім поле «сума», у якой запішам сумарны бал (апісанне структуры было разабрана ў прыкладзе 17.8).
  3. Для рашэння задачы будзем выкарыстоўваць алгарытм сартавання простымі ўстаўкамі.
  4. Створым кампаратар (функцыю параўнання), якая будзе параўноўваць дзве структуры па полі сумы балаў.
  5. Вывад выніку.
IV. Апісанне пераменных:: n – int, a –  vector<student>.

Кампаратар — гэта адносіны парадку. Як функцыя ён павінен задавальняць аксіёмы адносінаў парадку:

  • функцыя з’яўляецца дэтэрмінаванай: comp(a,b) для канкрэтных a і b заўсёды вяртае адзін і той жа вынік;
  • функцыя валодае ўласцівасцю транзітыўнасці: comp(a,b) && comp(b,c) абазначае тое ж самае, што comp(a,c) (у самым простым выпадку, калі a < b і b < c, то a < c);
  • функцыя валодае ўласцівасцю антысіметрычнасці: omp(a,b) &&  comp(b,a) абазначае, што а = b.

Прыклад 18.17.

V. Праграма:

#include <iostream>

#include <vector>

#include <cstdlib>

#include <ctime>

 

bool comp(int x, int y)

{

  return (% 2 < y % 2);

}

 

using namespace std;

 

int main()

{

  srand(time(NULL));

  int n;

  cout << "n = ";

  cin >> n;

  vector <int> a(n);

  cout << "chisla:" << endl;

  for (int i = 0; i < n; i++){

    a[i] = rand() % 100;

    cout << a[i] << " ";

  }

  cout << endl << "sort" << endl;

  for (int k = 1; k < n; k++)

    for (int i = 0; i < n - k; i++)

      if (!comp(a[i], a[+ 1]))

       swap(a[i], a[+ 1]);

  for (int i = 0; i < n; i++)

    cout << a[i] << " ";

  cout << endl;

  return 0;

}

VI. Тэсціраванне.

Прыклад 18.18. Фрагмент праграмы:

int i = 0, j = n - 1;

while (<= j) {

  while (a[i] % 2 == 0)

    i++;

  while (a[j] % 2)

    j--;

  if (<= j) {

    swap (a[i], a[j]);

    i++;

    j--;

  }

}

Прыклад 18.19.

 V. Праграма:

#include <iostream>

#include <vector>

#include <string>

#include <fstream>

#include <windows.h>

 

using namespace std;

using namespace std::__cxx11;

 

int kol_a(string s)

{

  int k = 0;

  for (int i = 0; i < s.length(); i++)

    if (s[i] == 'а' || s[i] == 'А')

      k++;

  return k;

}

 

bool comp(string x, string y)

{

  return (kol_a(x) > kol_a(y));

}

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  ifstream fin("input.txt");

  ofstream fout("output.txt");

  int n;

  fin >> n;

  fin.ignore();

  vector <string> a(n);

  for (int i = 0; i < n; i++)

    fin >> a[i];

  for (int k = 0; k < n - 1; k++){

    int nmax = k;

    for (int i = k + 1; i < n; i++)

      if (comp (a[i], a[nmax]))

       nmax = i;

    swap(a[k], a[nmax]);

  }

  for (int i = 0; i < n; i++)

    fout << a[i] << endl;

  return 0;

}

 V. Тэсціраванне. У тэкставы файл запісаны словы з пункта  18.1.

      

Прыклад 18.20.

 V.  Фрагмент праграмы (функцыю vvod і бібліятэкі, што падключаюцца, гл. у прыкладзе 17.8):

struct student

{

  string fam, gorod;

  vector <int> otm = vector<int>(3);

  int summa;

};

bool comp(student x, student y)

{

  return (x.summa > y.summa);

}

 

int main()

{

  SetConsoleCP(1251);

  SetConsoleOutputCP(1251);

  vector <student> a;

  vvod (a);

  ofstream fout ("output.txt");

  for (int k = 1; k < a.size(); k++){

    int i = k;

    while (> 0 && 

        !comp(a[- 1], a[i])){

      swap(a[- 1], a[i]);

      i--;

    }

  }

  for (int i = 0; i < a.size(); i++){

    fout << a[i].fam << '\t';

    fout << a[i].gorod << '\t';

    fout << a[i].summa << endl;

  }

  return 0;

}


     VI. Тэсціраванне. Выкарыстоўваецца тэкставы файл з прыкладу 17.8.