6228

Порівняння загальних характеристик роботи різних методів сортування

Курсовая

Информатика, кибернетика и программирование

Вступ В даний час обчислювальна техніка проникла практично в усі сфери людської діяльності. За допомогою ЕОМ можна вирішувати найрізноманітніші завдання. Але для того, щоб вирішити поставлену задачу, необхідно вказати послідовність дій, виконання як...

Украинкский

2012-12-30

203 KB

15 чел.

Вступ

В даний час обчислювальна техніка проникла практично в усі сфери людської діяльності. За допомогою ЕОМ можна вирішувати найрізноманітніші завдання. Але для того, щоб вирішити поставлену задачу, необхідно вказати послідовність дій, виконання яких приведе до необхідного результату, - скласти програму. Для зручності роботи з ЕОМ ця операція проводиться за допомогою мов програмування (високого або низького рівня).

Один із широко використовуваних мов програмування - це Visual C + +, який можна використовувати для написання програм, що працюють в операційному середовищі Windows. На даний час однієї з найпоширеніших його версій є Microsoft Visual C + +, і середовище програмування Visual studio.Середовище програмування Visual studio дозволяє створювати тексти програм, компілювати їх, знаходити помилки і оперативно їх виправляти; компонувати програми з окремих частин, включаючи стандартні модулі, налагоджувати і виконувати налагоджену програму.

Використовуючи перераховані можливості, можна створювати різні прикладні програми, наприклад, такі, як програма, написана при виконанні даної курсової роботи.


1.ВІДОМОСТІ ПРО МЕТОДИ СОРТУВАННЯ

Для вирішення багатьох завдань зручно спочатку упорядкувати дані за певною ознакою, так можна прискорити пошук деякого об'єкту. Наприклад, в преферансі гравці розкладають карти по мастям і за значенням. Так легше визначити, яких карт не вистачає. Або візьмемо будь енциклопедичний словник - статті в ньому впорядковані в алфавітному порядку.

Перегруповування заданої множини об'єктів в певному порядку називають сортуванням.

Чому сортування приділяється велика увага? Ви це зрозумієте, прочитавши цитати двох великих людей.

"Навіть якщо б сортування була майже марна, знайшлася б маса причин зайнятися нею! Винахідливі методи сортування говорять про те, що вона і сама по собі цікава як об'єкт дослідження." / Д. Кнут /

"Складається враження, що можна побудувати цілий курс програмування, вибираючи приклади тільки із завдань сортування." / Н. Вірт /

Відмінною особливістю сортування є та обставина, що ефективність алгоритмів, що реалізують її, прямо пропорційна складності розуміння цього алгоритму. Іншими словами, чим легше для розуміння метод сортування масиву, тим нижче його ефективність.


2.АЛГОРИТМИ

2.1 Сортування методом бульбашки

Розташуємо масив зверху вниз, від нульового елемента - до останнього.

Ідея методу: крок сортування полягає в проході знизу вгору по масиву. По дорозі проглядаються пари сусідніх елементів. Якщо елементи деякої пари знаходяться в неправильному порядку, то міняємо їх місцями (Рис. 5.1).

Рисунок 2.1 – Принцип роботи сортування методом бульбашки

Після нульового проходу по масиву "вгорі" виявляється самий "легкий" елемент - звідси аналогія з бульбашкою (Рис. 5.2). Наступний прохід робиться до другого зверху елемента, таким чином другий за величиною елемент піднімається на правильну позицію.

Робимо проходи по все зменшується нижній частині масиву до тих пір, поки в ній не залишиться тільки один елемент. На цьому сортування закінчується, так як послідовність упорядкована за зростанням.(Рис.2.2)

Рисунок 2.2 – Результат нульового кроку сортування

Середнє число порівнянь та обмінів мають квадратичний порядок зростання: Theta (n2), звідси можна зробити висновок, що алгоритм бульбашки дуже повільний і малоефективний.

Тим не менш, у нього є величезний плюс: він простий і його можна по-всякому покращувати. Чим ми зараз і займемося.

По-перше, розглянемо ситуацію, коли на якому-небудь з проходів не відбулося жодного обміну. Що це означає?

Це означає, що всі пари розташовані в правильному порядку, так що масив вже відсортований. І продовжувати процес не має сенсу (особливо, якщо масив був відсортований з самого початку!).

Отже, перше поліпшення алгоритму полягає в запам'ятовуванні, чи проводився на даному проході який-небудь обмін. Якщо ні - алгоритм закінчує роботу.

Процес поліпшення можна продовжити, якщо запам'ятовувати не тільки сам факт обміну, але і індекс останнього обміну k. Дійсно: всі пари сусіди елементів з індексами, меншими k, вже розташовані в потрібному порядку. Подальші проходи можна закінчувати на індексі k, замість того щоб рухатися до встановленої заздалегідь верхньої межі i.

Якісно інше поліпшення алгоритму можна отримати з наступного спостереження. Хоча легкий бульбашка знизу підніметься наверх за один прохід, важкі бульбашки опускаються зі мінімальною швидкістю: один крок за ітерацію. Так що масив 2 3 4 5 6 1 буде відсортований за 1 прохід, а сортування послідовності 6 1 2 3 4 5 зажадає 5 проходів.

Щоб уникнути подібного ефекту, можна змінювати напрямок наступних один за іншим проходів. Одержаний алгоритм іноді називають "шейкер-сортуванням".

Наскільки описані зміни вплинули на ефективність методу? Середня кількість порівнянь, хоч і зменшилася, але залишається O (n2), в той час як число обмінів не помінялося взагалі ніяк. Середнє (воно ж найгірше) кількість операцій залишається квадратичним.

Додаткова пам'ять, очевидно, не потрібно. Поведінка удосконаленого (але не початкового) методу досить природне, майже відсортований масив буде відсортований набагато швидше випадкового. Сортування бульбашкою стійка, проте шейкер-сортування втрачає цю якість.

На практиці метод бульбашки, навіть з поліпшеннями, працює, на жаль, занадто повільно. А тому - майже не застосовується.

2.2 Сортування методом Шелла

Сортування Шелла є досить цікавою модифікацією алгоритму сортування простими вставками.

Розглянемо наступний алгоритм сортування масиву a [0] .. a [15] (Рис. 5.3).

Рисунок 2.3 – Початковий стан масиву а

  1.  Спочатку сортуємо простими вставками кожні 8 груп з 2-х елементів (a [0], a [8 [), (a [1], a [9]), ... , (а [7], a [15]) (Рис. 5.4).

Рисунок 2.4 – Схема роботи методу сортування Шелла

  1.  Потім сортуємо кожну з чотирьох груп по 4 елемента (a [0], a [4], a [8], a [12]), ..., (a [3], a [7], a [11] , a [15]) (Рис. 5.5).

Рисунок 2.5 – Другий шаг сортування

В нульової групи будуть елементи 4, 12, 13, 18, в першій - 3, 5, 8, 9 тощо.

  1.  Далі сортуємо 2 групи по 8 елементів, починаючи з (a [0], a [2], a [4], a [6], a [8], a [10], a [12], a [14] ) (Рис. 5.6).

Рисунок 2.6 – Сортування груп елементів

  1.  В кінці сортуємо вставками всі 16 елементів (Рис. 5.7).

Рисунок 2.7 – Результат сортування методом Шелла

Очевидно, лише останнє сортування необхідне, щоб розташувати всі елементи по своїх місцях. Так навіщо потрібні інші?

Насправді вони просувають елементи максимально близько до відповідних позицій, так що в останній стадії число переміщень буде вельми невелика. Послідовність і так майже відсортована. Прискорення підтверджено численними дослідженнями і на практиці виявляється досить суттєвим.

Єдиною характеристикою сортування Шелла є приріст - відстань між сортованими елементами, в залежності від проходу. В кінці прирощення завжди дорівнює одиниці - метод завершується звичайної сортуванням вставками, але саме послідовність збільшень визначає зростання ефективності.

Використаний в прикладі набір ..., 8, 4, 2, 1 - непоганий вибір, особливо, коли кількість елементів - ступінь двійки.

При використанні таких приростів середня кількість операцій: O (n7 / 6), в гіршому випадку - порядку O (n4 / 3).

Звернемо увагу на те, що послідовність обчислюється в порядку, протилежному використовуваному: inc [0] = 1, inc [1] = 5, ... Формула дає спочатку менші числа, потім все більші і більші, у той час як відстань між сортованими елементами, навпаки, має зменшуватися. Тому масив приростів inc обчислюється перед запуском власне сортування до максимальної відстані між елементами, яке буде першим кроком в сортуванні Шелла. Потім його значення використовуються в зворотному порядку.

2.3 Швидке сортування

Опис алгоритму:

  1.  вибрати елемент, званий опорним.
  2.  порівняти всі інші елементи з опорним, на підставі порівняння розбити безліч на три - «менші опорного», «рівні» та «великі», розташувати їх у порядку менші-рівні-великі.
  3.  повторити рекурсивно для «менших» і «великих».

Примітка: на практиці звичайно поділяють сортовані безліч не на три, а на дві частини: наприклад, «менші опорного» і «рівні і великі». Такий підхід в загальному випадку виявляється ефективніше, тому що для здійснення такого поділу достатньо одного проходу по сортованому безлічі і однократного обміну лише деяких обраних елементів.

Алгоритм швидкого сортування використовує стратегію «розділяй і володарюй». Кроки алгоритму наступні:

  1.  Вибираємо в масиві деякий елемент, який будемо називати опорним елементом. З точки зору коректності алгоритму вибір опорного елемента байдужий. З точки зору підвищення ефективності алгоритму вибиратися повинна медіана, але без додаткових відомостей про сортованих даних її зазвичай неможливо отримати. Відомі стратегії: вибирати постійно один і той же елемент, наприклад, середній або останній по положенню; вибирати елемент з випадково вибраним індексом.
  2.  Операція поділу масиву: реорганізуємо масив таким чином, щоб всі елементи, менші або рівні опорному елементу, виявилися зліва від нього, а всі елементи, великі опорного - праворуч від нього. Звичайний алгоритм операції:
  3.  Два індексу - l і r, прирівнюються до мінімального і максимального індексу розділяється масиву відповідно.
  4.  Обчислюється індекс опорного елемента m.
  5.  Індекс l послідовно збільшується до тих пір, поки l-й елемент не перевищить опорний.
  6.  Індекс r послідовно зменшується до тих пір, поки r-й елемент не виявиться менше або дорівнює опорному.
  7.  Якщо r = l - знайдена середина масиву - операція поділу закінчена, обидва індекси вказують на опорний елемент.
  8.  Якщо l <r - знайдену пару елементів потрібно обміняти місцями і продовжити операцію поділу з тих значень l і r, які були досягнуті. Слід врахувати, що якщо яка-небудь кордон (l або r) дійшла до опорного елемента, то при обміні значення m змінюється на r-й або l-й елемент відповідно.
  9.  Рекурсивно упорядковуємо подмассіва, що лежать ліворуч і праворуч від опорного елемента.

Базою рекурсії є набори, що складаються з одного або двох елементів. Перший повертається в початковому вигляді, в другому, при необхідності, сортування зводиться до перестановки двох елементів. Всі такі відрізки вже впорядковані в процесі поділу.

Оскільки в кожній ітерації (на кожному наступному рівні рекурсії) довжина оброблюваного відрізка масиву зменшується, щонайменше, на одиницю, термінальна гілку рекурсії буде досягнута завжди і обробка гарантовано завершиться.

QuickSort є істотно поліпшеним варіантом алгоритму сортування за допомогою прямого обміну (його варіанти відомі як «Бульбашкова сортування» та «Шейкерная сортування»), відомого, зокрема, своєї низькою ефективністю. Принципова відмінність полягає в тому, що після кожного проходу елементи діляться на дві незалежні групи. Цікавий факт: поліпшення самого неефективного прямого методу сортування дало в результаті ефективний покращений метод.

Кращий випадок. Для цього алгоритму найкращий випадок - якщо в кожній ітерації кожен з підмасивів ділився б на два рівних по величині масиву. В результаті кількість порівнянь, які робить швидкої сортуванням, було б дорівнює значенню рекурсивного вираження CN = 2CN / 2 + N, що в явному вираженні дає приблизно N lg N порівнянь. Це дало б найменший час сортування.

Середнє. Дає в середньому O (n log n) обмінів при упорядкуванні n елементів. В реальності саме така ситуація зазвичай має місце при випадковому порядку елементів і виборі опорного елемента з середини масиву або випадково.

На практиці (у випадку, коли обміни є більш витратною операцією, ніж порівняння) швидке сортування значно швидше, ніж інші алгоритми з оцінкою O (n lg n), через те, що внутрішній цикл алгоритму може бути ефективно реалізований майже на будь-архітектурі. 2CN / 2 покриває витрати по сортуванню двох отриманих підмасива; N - це вартість обробки кожного елемента, використовуючи один або інший вказівник. Відомо також, що приблизне значення цього виразу одно CN = N lg N.

Найгірший випадок. Найгіршим нагодою, очевидно, буде такою, при якому на кожному етапі масив буде розділятися на вироджений підмасив з одного опорного елемента і на підмасив з усіх інших елементів. Таке може статися, якщо як опорного на кожному етапі буде обраний елемент або найменший, або найбільший з усіх оброблюваних.

Найгірший випадок дає O (n ²) обмінів. Але кількість обмінів і, відповідно, час роботи - це не найбільший його недолік. Гірше те, що в такому випадку глибина рекурсії при виконанні алгоритму досягне n, що буде означати n-кратне збереження адреси повернення і локальних змінних процедури поділу масивів. Для великих значень n найгірший випадок може привести до вичерпання пам'яті під час роботи алгоритму. Втім, на більшості реальних даних можна знайти рішення, які мінімізують ймовірність того, що знадобиться квадратичне час.


2.4Сортування вибором

Ідея методу полягає в тому, щоб створювати відсортовану послідовність шляхом приєднання до неї одного елемента за іншим у правильному порядку.

Будемо будувати готову послідовність, починаючи з лівого кінця масиву. Алгоритм складається з n послідовних кроків, починаючи від нульового і закінчуючи (n-1)-му.

На i-му кроці вибираємо найменший з елементів a [i] ... a [n] і міняємо його місцями з a [i]. Послідовність кроків при n = 5 зображена на Рис. 5.8.

Рисунок 2.8 – Приклад сортування вибором

Незалежно від номера поточного кроку i, послідовність a [0] ... a [i] (виділена курсивом) є впорядкованою. Таким чином, на (n-1)-му кроці вся послідовність, крім a [n] виявляється відсортованої, а a [n] стоїть на останньому місці по праву: все менші елементи вже пішли вліво.

Для знаходження найменшого елемента з n + 1 ,що розглядаються,алгоритм робить n порівнянь. З урахуванням того, що кількість розглянутих на черговому кроці елементів зменшується на одиницю, загальна кількість операцій обчислюється за формулою (2.1):

  (2.1)

Таким чином, так як число обмінів завжди буде менше числа порівнянь, час сортування зростає квадратично щодо кількості елементів.

Алгоритм не використовує додаткової пам'яті: всі операції відбуваються "на місці".

Розглянемо послідовність з трьох елементів, кожен з яких має два поля, а сортування йде за першою з них (Рис. 2.9).


Рисунок 2.9 – Сортування масивів з двома полями

Результат її сортування можна побачити вже після кроку 0, так як більше обмінів не буде. Порядок ключів 2a, 2b був змінений на 2b, 2a, так що метод нестійкий.

Якщо вхідні послідовність майже впорядкована, то порівнянь буде стільки ж, значить алгоритм поводиться неприродно.

2.5Сортування вставками

Сортування простими вставками в чомусь схожа на вищевикладені методи.

Аналогічним чином робляться проходи по частині масиву, і аналогічним же чином на його початку "виростає" відсортована послідовність.

Однак у сортуванні бульбашкою або вибором можна було чітко заявити, що на i-му кроці елементи a [0] ... a [i] стоять на правильних місцях і нікуди більше не перемістяться. Тут же подібне твердження буде більш слабким: послідовність a [0] ... a [i] впорядкована. При цьому по ходу алгоритму в неї будуть вставлятися (див. назву методу) все нові елементи.

Будемо розбирати алгоритм, розглядаючи його дії на i-му кроці. Як говорилося вище, послідовність до цього моменту розділена на дві частини: готову a [0] ... a [i] і невпорядковану a [i +1] ... a [n].

На наступному, (i +1)-м кожному кроці алгоритму беремо a [i +1] і вставляємо на потрібне місце в готову частину масиву.

Пошук відповідного місця для чергового елемента вхідної послідовності здійснюється шляхом послідовних порівнянь з елементом, що стоять перед ним.

В залежності від результату порівняння елемент або залишається на поточному місці (вставка завершена), або вони міняються місцями і процес повторюється (Рис. 5.10).

Рисунок 2.10 – Процес сортування вставками

Таким чином, в процесі вставки ми "просіваємо" елемент x до початку масиву, зупиняючись у випадку, коли знайдено елемент, менший x або досягнуто початок послідовності.

Аналогічно сортуванні вибором, середнє, а також найгірше число порівнянь і пересилань оцінюються як Theta (n2), додаткова пам'ять при цьому не використовується.

Хорошим показником сортування є дуже природна поведінка: майже відсортований масив, буде дуже швидко відсортовано. Це, вкупі зі стійкістю алгоритму, робить метод хорошим вибором у відповідних ситуаціях.

Алгоритм можна злегка поліпшити. Зауважимо, що на кожному кроці внутрішнього циклу перевіряються 2 умови. Можна об'єднати з в одне, поставивши в початок масиву спеціальний сторожовий елемент. Він повинен бути свідомо менше всіх інших елементів масиву. Тоді при j = 0 буде свідомо вірно a [0] <= x. Цикл зупиниться на нульовому елементі, що й було метою умови j> = 0.

Таким чином, сортування відбуватиметься правильним чином, а у внутрішньому циклі стане на одне порівняння менше. З урахуванням того, що воно проводилося Theta (n2) раз, це - реальна перевага. Однак, відсортований масив буде не повний, так як з нього зникло перше число. Для закінчення сортування це число слід повернути назад, а потім вставити в відсортовану послідовність a [1] ... a [n] (Рис. 5.11).

Рисунок 2.11 – Закінчення процесу сортування


3.ІНСТРУКЦІЯ КОРИСТУВАЧА

3.1 Сортування методом Шелла

У 1959 році Д.Л.Шелл запропонував замість систематичного включення елемента з індексом i в підмасив попередніх йому елементів (цей спосіб суперечить принципу "балансування", чому і не дозволяє отримати ефективний алгоритм) включати цей елемент в підсписок, що містить елементи з індексами ih, i-2h, i-3h і т.д., де h - деяка натуральна постійна. Таким чином формується масив, в якому h-серії елементів, віддалених один від одного на відстань h, сортуються окремо:

Після того, як розсортовані непересічні h-серії, процес поновлюється з новим значенням h '<h. Попереднє сортування серій з відстанню h значно прискорює сортування серій з відстанню h '.

Доведено, що максимальна складність алгоритму Шелла становить O (n5 / 4). Так як

   (3.1)

то цей вид сортування придатний для послідовностей, що мають приблизно до 70 тис. елементів.

3.1.1 Покращення

При виборі опорного елемента з даного діапазону випадковим чином гірший випадок стає дуже малоймовірним і очікуваний час виконання алгоритму сортування - O (n lg n).

Вибирати опорним елементом середній з трьох (першого, середнього і останнього елементів). Такий вибір також спрямований проти гіршого випадку.

Щоб уникнути досягнення небезпечної глибини рекурсії в гіршому випадку (або при наближенні до нього) можлива модифікація алгоритму, що усуває одну гілку рекурсії: замість того, щоб після поділу масиву викликати рекурсивну процедуру поділу для обох знайдених підмасива, рекурсивний виклик робиться тільки для меншого підмасива, а більший обробляється в циклі в межах цього ж виклику процедури. З точки зору ефективності в середньому разі різниці практично немає: накладні витрати на додатковий рекурсивний виклик і на організацію порівняння довжин підмасива і циклу - приблизно одного порядку. Зате глибина рекурсії ні за яких обставин не перевищить log2n, а в гіршому випадку виродженого поділу вона взагалі буде не більше 2 - вся обробка пройде в циклі першого рівня рекурсії.

Розбивати масив не на дві, а на три частини (див. Dual Pivot Quicksort).

3.1.2 Переваги:

Один з найбільш швидкодіючих (на практиці) з алгоритмів внутрішнього сортування загального призначення.

Простий в реалізації.

Потребує лише додаткової пам'яті для своєї роботи. (Не покращений рекурсивний алгоритм у гіршому випадку пам'яті)

Добре поєднується з механізмами кешування і віртуальної пам'яті.

Існує ефективна модифікація (алгоритм Седжвіка) для сортування рядків - спочатку порівняння з опорним елементом тільки за нульовим символу рядка, далі застосування аналогічної сортування для «більшого» і «меншого» масивів теж за нульовим символу, і для «рівного» масиву по вже першого символу .


3.1.3 Недоліки:

Сильно деградує за швидкістю (до) при невдалих виборах опорних елементів, що може трапитися при невдалих вхідних даних. Цього можна уникнути, використовуючи такі модифікації алгоритму, як Introsort, або вероятностно, вибираючи опорний елемент випадково, а не фіксованим чином.

Наївна реалізація алгоритму може привести до помилки переповнення стека, так як їй може знадобитися зробити вкладених рекурсивних викликів. У покращених реалізаціях, в яких рекурсивний виклик відбувається тільки для сортування меншою з двох частин масиву, глибина рекурсії гарантовано не перевищить.

Нестійкий - якщо потрібна стійкість, доводиться розширювати ключ.

Розглянемо роботу процедури для масиву a [0] ... a [6] і опорного елемента p = a [3].

Рисунок 5.8 – Приклад роботи процедури сортування

3.2 Сортування вставками

У функцію InsertionSort передається масив A і довжина списку n. Розглянемо i-ий прохід (1 <i <n-1). Підсписок від A [0] до A [i-1] вже відсортований за зростанням. Як вставляється (TARGET) виберемо елемент A [i] і будемо просувати його до початку списку, порівнюючи з елементами A [i-1], A [i-2] і т.д. Перегляд закінчується на елементі A [j], який менше або дорівнює TARGET або знаходиться на початку списку (j = 0). У міру просування до початку списку кожний елемент зсувається вправо (A [j] = A [j-1]). Коли відповідне місце для A [i] буде знайдено, цей елемент вставляється в точку j.

Сортування вставками вимагає фіксованого числа проходів. На n-1 проходах вставляються елементи від A [1] до A [n-1]. На i-му проході вставки виробляються в підсписок A [0]-A [i] і вимагають в середньому i / 2 порівнянь. Загальне число порівнянь єдине:

(3.2)

 

На відміну від інших методів, сортування вставками не використовує обміни. Складність алгоритму вимірюється числом порівнянь і дорівнює O (n2). Найкращий випадок - коли початковий список вже відсортований. Тоді на i-му проході вставка здійснюється в точці A [i], а загальне число порівнянь одно n-1, тобто складність становить O (n). Найгірший випадок виникає, коли список відсортований за спаданням. Тоді кожна вставка відбувається в точці A [0] і вимагає i порівнянь. Загальне число порівнянь одно n (n-1) / 2, тобто складність становить O (n2).

В принципі, алгоритм сортування вставками можна значно прискорити. Для цього слід не зрушувати елементи по одному, як це продемонстровано в наведеному вище прикладі, а знаходити потрібний елемент за допомогою бінарного пошуку, описаного в попередньому номері (тобто, в циклі розбиваючи список на дві рівні частини, поки в списку не залишиться один- два елементи), а для зсування використовувати функції копіювання пам'яті. Такий підхід дає досить високу продуктивність на невеликих масивах. Основним вузьким місцем у даному випадку є саме копіювання пам'яті. Поки що обсяг копійованих даних (близько половини розміру масиву) можна порівняти з розміром кеша процесора 1 рівня, продуктивність цього методу досить висока. Але через множинних непродуктивних повторів копіювання, цей спосіб менш кращий, ніж метод «швидкої» сортування, описаний в наступному розділі. Цей же метод можна рекомендувати у разі щодо статичного масиву, в який зрідка проводиться вставка одного-двох елементів.

3.3 Сортування вибором

Оцінимо часову складність даного методу, використовуючи в якості основної операції операцію порівняння.

Для пошуку мінімального елемента в кожному проході потрібно виконати: n-1, n-2, 1 операцій порівняння, тобто всього n (n-1) / 2 операцій порівняння. Отже, обчислювальна складність даного методу O (n2). Причому час сортування не залежить від вихідного порядку елементів.


Рисунок 3.1 – Алгоритм сортування вибором

3.4 Метод швидкого сортування

Загальний аналіз ефективності «швидкої» сортування досить важкий. Буде краще показати її обчислювальну складність, підрахувавши число порівнянь при деяких ідеальних припущеннях. Припустимо, що n - ступінь двійки, n = 2k (k = log2n), а центральний елемент розташовується точно посередині кожного списку і розбиває його на два підсписки приблизно однакової довжини.

При першому скануванні проводиться n-1 порівнянь. В результаті створюються два підсписки розміром n / 2. На наступній фазі обробка кожного підсписки вимагає приблизно n / 2 порівнянь. Загальне число порівнянь на цій фазі дорівнює 2 (n / 2) = n. На наступній фазі обробляються чотири підсписки, що вимагає 4 (n / 4) порівнянь, і т.д. Зрештою процес розбиття припиняється після k проходів, коли вийшли підсписки містять по одному елементу. Загальне число порівнянь приблизно дорівнює n + 2 (n / 2) + 4 (n / 4) + ... + N (n / n) = n + n + ... + N = n * k = n * log2n

Для списку загального вигляду обчислювальна складність «швидкої» сортування дорівнює O (n log2 n). Ідеальний випадок, який ми тільки що розглянули, фактично виникає тоді, коли масив вже відсортований за зростанням. Тоді центральний елемент потрапляє точно в середину кожного підсписки.

Якщо масив відсортований за спаданням, то на першому проході центральний елемент виявляється на середині списку і змінюється місцями з кожним елементом як у першому, так і в другому підсписки. Результуючий список майже відсортований, алгоритм має складність порядку O (n log2n).(рис. 3.2.1)

«Рисунок 3.2.1−опис методу швидкого сортування»

Найгіршим сценарієм для «швидкої» сортування буде той, при якому центральний елемент весь час потрапляє в одноелементні подспісок, а всі інші елементи залишаються в другому підсписки. Це відбувається тоді, коли центральним завжди є найменший елемент. Розглянемо послідовність 3, 8, 1, 5, 9.

На першому проході проводиться n порівнянь, а більший подспісок містить n-1 елементів. На наступному проході цей подспісок вимагає n-1 порівнянь і дає подспісок з n-2 елементів і т.д. Загальне число порівнянь одно: n + n-1 + n-2 + ... + 2 = n (n +1) / 2 - 1

Складність найгіршого випадку дорівнює O (n2), тобто не краще, ніж для сортувань вставками і вибором. Однак цей випадок є патологічним і малоймовірний на практиці. Загалом, середня продуктивність «швидкої» сортування вище, ніж у всіх розглянутих нами сортувань.

Алгоритм QuickSort вибирається за основу в більшості універсальних сортують утиліт. Якщо ви не можете змиритися з продуктивністю найгіршого випадку, використовуйте пірамідальну сортування - більш стійкий алгоритм, складність якого дорівнює O (n log2n) і залежить тільки від розміру списку.


3.4 Метод сортування бульбашкою

Алгоритм метод бульбашки - найбільш простий метод сортування масиву. через

своєї простоти цей метод не дуже ефективний і вимагає процесорного часу

більше, ніж інші методи. Однак для сортування невеликих масивів

використання методу бульбашки прийнятно. Припустимо, що масив сортується в

порядку зростання, тоді метод бульбашки використовує цикл за значеннями масиву,

переміщаючи поступово найбільше значення в кінець масиву (подібно до того, як в

воді спливає на поверхню пляшечку).

Сортування методом бульбашки займає 61,3 секунд.


ВЫВОДЫ

Написание курсовой работы позволило закрепить теоретические знания языка С++. Были приобретены основные навыки работы со средой программирования Microsoft Visual Studio 2008 а конкретней с СRL Windows Forms. В курсовой работе не только показаны все способы расставить 8 ферзей на шахматной доске ,и посчитано сколько таких расстановок существует ,но и реализован простой ,но в тоже время удобный интерфейс , в котором пользователь может в понятном виде просмотреть все расстановки.

ПЕРЕЧЕНЬ ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

1. Страуструп, Б. Язык программирования С++. Часть 1 [Текст] / Б. Страуструп; перевод с англ. – К.: ДиаСофт, 1993. – 264 с.

2. Страуструп, Б. Язык программирования С++. Часть 2 [Текст] / Б. Страуструп; перевод с англ. – К.: ДиаСофт, 1993. – 296 с.

3. Соловьева Ф.И. Введение в теорию кодирования: Учебное пособие/ Новосибирск. гос. ун-т.  Новосибирск, 2006. с.127.

4. Павловская Т.А.: «C/C++. Программирование на языке высокого уровня – СПб.: Питер, 2004. – 461 с.;

5.        Пархомов, Б. С/С++ и МS Visual C++ 2008 для начинающих , 2009. 609 с.

6.       Новиков Ф.А.  Дискретная математика для программистов, 2006. 600 с.

ПРИЛОЖЕНИЕ А

Файл «Form1.h» :

#pragma once

#include <string>

#include <fstream>

#include <vector>

#include "Chess.h"

const char endStr[] = {13,10,0} ; //конец строки для textBox1

namespace KYYYRSAAAVVVV {

 using namespace System;

 using namespace System::ComponentModel;

 using namespace System::Collections;

 using namespace System::Windows::Forms;

 using namespace System::Data;

 using namespace System::Drawing;

 /// <summary>

 /// Summary for Form1

 ///

 /// WARNING: If you change the name of this class, you will need to change the

 ///          'Resource File Name' property for the managed resource compiler tool

 ///          associated with all .resx files this class depends on.  Otherwise,

 ///          the designers will not be able to interact properly with localized

 ///          resources associated with this form.

 /// </summary>

 public ref class Form1 : public System::Windows::Forms::Form

{

 public:

 Form1(void)

 {

  InitializeComponent();

  //

  //TODO: Add the constructor code here

  //

  this->currentElement=0;

  this->readFromClass(0);

 }

 protected:

 /// <summary>

 /// Clean up any resources being used.

 /// </summary>

 ~Form1()

 {

  if (components)

  {

   delete components;

  }

 }

 private: System::Windows::Forms::Button^  button1;

 protected:

 private: System::Windows::Forms::RichTextBox^  richTextBox1;

 private: System::Windows::Forms::Button^  button3;

 private: System::Windows::Forms::Button^  button4;

 private: System::Windows::Forms::Label^  label1;

 private: int  currentElement;//номер элемента, который на экране сейчас.

 private:

 /// <summary>

 /// Required designer variable.

 /// </summary>

 System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

 /// <summary>

 /// Required method for Designer support - do not modify

 /// the contents of this method with the code editor.

 /// </summary>

 void InitializeComponent(void)

 {

  this->button1 = (gcnew System::Windows::Forms::Button());

  this->richTextBox1 = (gcnew System::Windows::Forms::RichTextBox());

  this->button3 = (gcnew System::Windows::Forms::Button());

  this->button4 = (gcnew System::Windows::Forms::Button());

  this->label1 = (gcnew System::Windows::Forms::Label());

  this->SuspendLayout();

  //

  // button1

  //

  this->button1->Location = System::Drawing::Point(0, 244);

  this->button1->Name = L"button1";

  this->button1->Size = System::Drawing::Size(75, 23);

  this->button1->TabIndex = 0;

  this->button1->Text = L"выход";

  this->button1->UseVisualStyleBackColor = true;

  this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);

  //

  // richTextBox1

  //

  this->richTextBox1->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 14, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,

   static_cast<System::Byte>(204)));

  this->richTextBox1->Location = System::Drawing::Point(12, 12);

  this->richTextBox1->Name = L"richTextBox1";

  this->richTextBox1->ScrollBars = System::Windows::Forms::RichTextBoxScrollBars::Horizontal;

  this->richTextBox1->Size = System::Drawing::Size(292, 220);

  this->richTextBox1->TabIndex = 2;

  this->richTextBox1->Text = L"";

  this->richTextBox1->TextChanged += gcnew System::EventHandler(this, &Form1::richTextBox1_TextChanged);

  //

  // button3

  //

  this->button3->Location = System::Drawing::Point(268, 241);

  this->button3->Name = L"button3";

  this->button3->Size = System::Drawing::Size(36, 26);

  this->button3->TabIndex = 4;

  this->button3->Text = L">>";

  this->button3->UseVisualStyleBackColor = true;

  this->button3->Click += gcnew System::EventHandler(this, &Form1::button3_Click);

  //

  // button4

  //

  this->button4->Location = System::Drawing::Point(87, 238);

  this->button4->Name = L"button4";

  this->button4->Size = System::Drawing::Size(33, 29);

  this->button4->TabIndex = 5;

  this->button4->Text = L"<<";

  this->button4->UseVisualStyleBackColor = true;

  this->button4->Click += gcnew System::EventHandler(this, &Form1::button4_Click);

  //

  // label1

  //

  this->label1->AutoSize = true;

  this->label1->Location = System::Drawing::Point(178, 248);

  this->label1->Name = L"label1";

  this->label1->Size = System::Drawing::Size(37, 13);

  this->label1->TabIndex = 6;

  this->label1->Text = L"0 из 0";

  //

  // Form1

  //

  this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);

  this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;

  this->ClientSize = System::Drawing::Size(316, 279);

  this->Controls->Add(this->label1);

  this->Controls->Add(this->button4);

  this->Controls->Add(this->button3);

  this->Controls->Add(this->richTextBox1);

  this->Controls->Add(this->button1);

  this->Name = L"Form1";

  this->Text = L"Шахматы ! Курсовая Корженко";

  this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);

  this->ResumeLayout(false);

  this->PerformLayout();

 }

#pragma endregion

 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) { Form1::Close();

   }

 private: System::Void textBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {

   }

 private: System::Void printPreviewDialog1_Load(System::Object^  sender, System::EventArgs^  e) {

   }

private: System::Void openFileDialog1_FileOk(System::Object^  sender, System::ComponentModel::CancelEventArgs^  e) {

  }

private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {

  }

private: System::Void файлToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {

  }

private: System::Void выходToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) { Form1::Close();

  }

private: System::Void richTextBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {

  }

private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {

  }

  

private: System::Void readFromClass(int a) {

   this->label1->Text=a.ToString();

   this->label1->Text+=" из ";

   this->label1->Text+=(Chess::n-1).ToString();

   this->richTextBox1->Text = Chess::getOut(a);

  }

private: System::Void button4_Click(System::Object^  sender, System::EventArgs^  e) {

   if(this->currentElement>0){

    this->currentElement--;

    this->readFromClass(this->currentElement);

   }

  }

private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {

   if(this->currentElement<Chess::n-1){

    this->currentElement++;

    this->readFromClass(this->currentElement);

   }

  }

};

}

Файл «Chess.h» :

#pragma once

ref class Chess

{

 

public:

 static char ** mas;//массив

 static int N=8;//размер доски

 static int stringSize=1000;//

 static System::String^ getOut(int a);//получить из массива

 static int n;//кол-во расстановок

 static int currentStringToWrite=0;//

 static bool Check(int K, int Y);

 static char *X=new char[N];//

 static void MainProc(int k);

 static void Display();

 static int Count=0;

Chess(void);

Chess(int);

};

Файл «Chess.cpp» :

#include "StdAfx.h"

#include "Chess.h"

//System::String^ Chess::out= gcnew String();//для массива ответов

Chess::Chess(void)

{

}

Chess::Chess(int a){

Chess::n=a;

Chess::mas=new char*[a];

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

 Chess::mas[i]=new char[Chess::stringSize];

}

Chess::MainProc(0);

 

}

System::String^ Chess::getOut(int a){

 if(a>Chess::n) throw 99;

System::String^ out = gcnew System::String("");//создает пустую строку

 for(int i=0;i<Chess::stringSize && mas[a][i]!='\0';i++){

 if(mas[a][i]=='Q')

  out+=" Q ";

 if(mas[a][i]=='\n')

  out+="\n";

 if(mas[a][i]=='*')

  out+=" \x17\x17 ";

}

 return out;

}

bool Chess::Check(int K, int Y)

{

 int i=0;

 while ((i < K) && (Y != X[i]) && (abs(K - i) != abs(Y - X[i]))) i++;

 return (i == K);

}

void Chess::MainProc(int k)

{

 for (int y = 0; y<Chess::N; y++)

 if (Chess::Check(k, y))

 {

  Chess::X[k] = y;

  if (k == (Chess::N - 1))

  {

   Chess::Display();

   Chess::Count++;

   Chess::n=Chess::Count;

  }

  Chess::MainProc(k + 1);

 }

}

void Chess::Display(){

 int num=0;//номер символа который сохраняем сейчас

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

{

 for(int j=0;j<N;j++)

 {  

  if(j==X[i])Chess::mas[currentStringToWrite][num]='Q';

  else Chess::mas[currentStringToWrite][num]='*';

  num++;

 }

 Chess::mas[currentStringToWrite][num]='\n';//перевод строки

 num++;

}

Chess::mas[currentStringToWrite][num]='\0';//end строки

Chess::currentStringToWrite++;

}

Файл «KYYYRSAAAVVVV.cpp» :

// KYYYRSAAAVVVV.cpp : main project file.

#include "stdafx.h"

#include "Form1.h"

#include "Chess.h"

using namespace KYYYRSAAAVVVV;

[STAThreadAttribute]

int main(array<System::String ^> ^args)

{

 // Enabling Windows XP visual effects before any controls are created

Application::EnableVisualStyles();

Application::SetCompatibleTextRenderingDefault(false);

Chess::Chess(100);

 // Create the main window and run it

Application::Run(gcnew Form1());

 return 0;

}

ПРИЛОЖЕНИЕ Б


 

А также другие работы, которые могут Вас заинтересовать

13472. Изучение методов получения заготовок литьем 1.02 MB
  Лабораторная работа №1 Изучение методов получения заготовок литьем Используя рисунки представленные в методических указаниях материалы лабораторных стендов а также рекомендуемую литературу изучить технологический процесс получения заготовок литьем и подготови...
13474. Изучение методов получения заготовок давлением (пластическим деформированием) 4.81 MB
  Лабораторная работа №2 Изучение методов получения заготовок давлением пластическим деформированием Используя рисунки представленные в методических указаниях материалы лабораторных стендов а также рекомендуемую литературу изучить технологический процесс по...
13475. Изучение технологического оснащения токарной обработки 1.05 MB
  Лабораторная работа №3 Изучение технологического оснащения токарной обработки. Используя рисунки представленные в методических указаниях материалы лабораторных стендов а также рекомендуемую литературу изучить средства технологического оснащения оборудование...
13476. Подготовка текста в Microsoft Word 838 KB
  Лабораторная работа Тема: Подготовка текста в Microsoft Word Цель работы: Научиться создавать таблицы и формулы работать с документом в режиме исправлений создавать формы бланки для проведения опросов и тестирования выполнять слияние документа с источником данных об...
13477. Объекты системы 1С:Предприятие 759.5 KB
  Объекты системы 1С:Предприятие В системе 1С:Предприятие можно выделить две основные составляющие: технологическая платформа; прикладные решения автоматизации различных участков деятельности которые создаются с помощью технологической платформы. В техн...
13478. Создание новой информационной базы 199 KB
  Документы Лабораторная работа Задача 1. Создание новой информационной базы. 1. Выполните Пуск|Программы|1C Предприятие 8.1|Конфигуратор. 2. В появившемся окне Запуск 1С:предприятия щелкните по кнопке Добавить. 3. В появившемся окне Добавление информационной базы/г
13479. Создание регистра накопления остатков 279.5 KB
  Регистры накопления Лабораторная работа Задача 1. Создание регистра накопления остатков. 1. Откройте базу МояБаза1 в режиме конфигуратора. 2. Создайте документ Поступление. В области шапки документа укажите один дополнительный реквизит – Заказчик тип данных – Спра...
13480. Организация непериодических регистров сведений 163 KB
  Регистры сведений Лабораторная работа Задача 1. Организация непериодических регистров сведений. Пусть в организации имеется несколько филиалов каждый из которых включает несколько подразделений. В каждом конкретном подразделении филиала определено ответственно