
- •Введение
- •1 Теоретический раздел
- •Определение списка
- •1.2 Свойства списка
- •1.3 Виды списков
- •1.3.1 Линейный односвязный список
- •1.3.2 Кольцевой односвязный список
- •1.3.3 Линейный двусвязный список
- •1.3.4 Кольцевой двусвязный список
- •1.3.5 Многосвязные списки
- •1.4 Описание компилятора Microsoft Visual Studio
- •1.5 Visual Studio 2010
- •1.6 Приложения Windows Forms
- •1.6.1 Графические элементы Windows Forms
- •1.6.1.1 Двухмерная векторная графика
- •1.6.1.2 Рисунки
- •1.6.1.3 Типографская разметка
- •1.6.2 Классы Windows Forms
- •1.7 Определение сортировки слиянием
- •1.8 Пример сортировки слиянием
- •1.9.1 Временя работы
- •1.9.2 Анализ времени работы сортировки слиянием через рекуррентное соотношение
- •1.10 Достоинства и недостатки сортировки слиянием
- •2 Проектный раздел
- •2.1 Постановка задачи
- •2.2 Алгоритм сортировки слиянием
- •3 Программный раздел
- •3.1 Архитектура программы
- •3.2 Описание структуры программы и её основных частей
- •3.3 Описание функций составных частей и связей между ними
- •Заключение
- •Список использованных источников
2.2 Алгоритм сортировки слиянием
Пример работы алгоритма сортировки слиянием для списка, состоящего из элементов 1, 2, 3, 4,..8 (рисунок 7).
Рисунок 7 – Изначальный неупорядоченный список
Происходит
слияние элементов до упорядоченных пар
(рисунок 8).
Рисунок 8 – Слияние до упорядоченных пар
Следующий этап – слияние до упорядоченных четверок (рисунок 9).
Рисунок 9 – Слияние до упорядоченных четверок
Завершающий
этап – слияние до упорядоченного списка
(рисунок 10).
Рисунок 10 – Слияние четверок в упорядоченный список
3 Программный раздел
3.1 Архитектура программы
Для
описания архитектуры программы, а также
взаимодействия компонентов в программе
Rational Rose
2003 были спроектированы диаграммы
прецедентов и последовательности, в
которых отображаются все возможные
действия пользователей в системе
(рисунки 11-13).
Рисунок 11 – Диаграмма прецедентов
Описание элементов диаграммы прецедентов:
пользователь (актер) - выполняет все действия по взаимодействию с приложением;
кнопка «Добавить» - добавление в список нового элемента и отображение списка;
кнопка «Сортировать» - сортировка списка и его отображение.
Рисунок
12 – Диаграмма последовательности для
прецедента «Кнопка ”Добавить”»
Рисунок 13– Диаграмма последовательности для прецедента «Кнопка ”Сортировать”»
3.2 Описание структуры программы и её основных частей
Программная компонента реализована в виде основной программы Tratata.cpp, написанной на языке C, в которой вызывается заголовочный файл Form1.h.
Общий
порядок работы таков: компилятор
Microsoft Visual
Studio 2010 языка C
компилирует программу Tratata.cpp; в ходе
компиляции происходит вызов заголовочного
файла Form1.h, затем обработка пользовательских
параметров, чтение входных данных,
подготовка входных данных для функции
преобразования типов переменных atoi, её
запуск с ожиданием завершения, чтение
выходных данных функции atoi, запуск
функций, с учетом выбора команд
пользователем, которые представлены в
виде кнопок в приложение Windows
Forms, «Добавить» или
«Сортировать», каждой кнопке соответствует
свой набор команд. В ходе завершения
работы функций происходит формирование
окончательного результата и вывод его
в форме в виде схематического изображения
списка. Таким образом, пользователь
взаимодействует с приложением Windows
Forms, а все функции выполняются
автоматически в файле Form1.h.
3.3 Описание функций составных частей и связей между ними
Программа реализует основную логику алгоритма сортировки слиянием, а также осуществляет ввод-вывод пользовательских и рабочих данных и интерфейс пользователя (вывод графических изображений). В ходе своей работы программа может использовать функции addnode, Length, FrontBackSplit, SortedMerge, MergeSort, atoi для выполнения ресурсоёмких вычислений или (в некоторых случаях) использовать ранее полученные результаты её работы.
Функция addnode выполняет операцию добавления элемента в список, для каждого нового элемента выделяется память, достаточная для его размещения, с помощью функции выделения динамической памяти malloc. Далее идет проверка того, удалось ли выделить запрашиваемое количество памяти. Это выполняется с помощью оператора if и условия (tnode != NULL). В случае выполнения, элемент будет добавлен, иначе нет. Вызов данной функции происходит при использование кнопки «Добавить». Далее представлен код самой кнопки, в которой используется описанная функция, код самой функции и ее блок-схема (рисунок 14):
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
char* str2 =
(char*)(void*)Marshal::StringToHGlobalAnsi(textBox1->Text);
int k = atoi(str2);
holoce = addnode(k, holoce);
paintSp(holoce);
}
Код функции: struct node *addnode(int number, struct node *next)
struct node *tnode;
tnode = (struct node*)malloc(sizeof(*tnode));
if(tnode != NULL) {
tnode->number = number;
tnode->next = next;
}
return
tnode;
}
Рисунок 14 - Блок-схема функции addnode
Функция
Length используется для определение длины
списка на данный момент. Происходит это
с использование цикла с предусловием
while и переменной count,
которая является счетчиком элементов
списка, переход к следующему элементу
осуществляется через указатель. В
результате функция возвращает целое
число – длину списка. Далее представлен
код функции и блок-схема (рисунок 15):
int Length(struct node* head) {
int count = 0;
struct node* current = head;
while (current != NULL) {
count++;
current = current->next;
}
return(count);}
Рисунок 15 - Блок-схема функции Length
Функция FrontBackSplit для разбиения имеющего списка на подсписки использует описанную выше функцию Length. Так как в программе реализована работа алгоритма сортировки слиянием, необходима функция, в ходе выполнения которой имеющийся список будет разбиваться на подсписки. В функции используются операторы условия if, цикл с известным количеством повторений for и указатели frontRef, backRef, которые являются результатами выполнения функции (разбиения на подсписки). Ниже фрагмент программы, на котором представлена реализация функции, и ее блок-схема (рисунок 16):
void FrontBackSplit(struct node* source,
struct node** frontRef,
struct node** backRef) {
int len = Length(source);
int i;
struct node* current = source;
if (len < 2) {
*frontRef = source;
*backRef = NULL;
}
else
{
int hopCount = (len-1)/2;
for (i = 0; i<hopCount; i++){
current = current->next;
}
*frontRef = source;
*backRef = current->next;
current->next = NULL;
}
}
Рисунок 16 - Блок-схема функции FrontBackSplit
Функция SortedMerge обеспечивает слияние упорядоченных подсписков в один результирующий с учетом отношения порядка. Происходит работа с указателями, операторами условия, так как функция является рекурсивной, то в ходе ее выполнения функция вызывает сама себя. В последующем SortedMerge будет использоваться в другой функции, MergeSort. Ниже представлен код функции и ее блок-схема (рисунок 17):
struct node* SortedMerge(struct node* a, struct node* b)
{
struct node* result = NULL;
if (a==NULL) return(b);
else if (b==NULL) return(a);
if (a->number <= b->number)
{ result = a;
result->next = SortedMerge(a->next, b);
}
else {
result = b;
result->next = SortedMerge(a, b->next);
}
return(result);
}
if
(b==NULL)
return(a);
2
1
2
1
Рисунок
17 - Блок-схема
функции
SortedMerge
Основная функция программы – это функция MergeSort, она осуществляет рекурсивную сортировку подсписков и их слияние в результирующий список благодаря функции SortedMerge, которую она вызывает, а также функция FrontBackSplit для разбиения списка на подсписки. В функции использовались указатели, операторы условия. В ходе выполнения происходит проверка длины списка, если список пуст или состоит из одного элемента, работа функции прекращается. Ниже представлен код самой функции и ее блок-схема (рисунок 18):
void MergeSort(struct node** headRef) {
struct node* head = *headRef;
struct node* a;
struct node* b;
// Вырожденный случай – длина списка равно 0 или 1
if ((head == NULL) || (head->next == NULL)) {
return;
}
FrontBackSplit(head, &a, &b); //Вызов функции разбиения списка
MergeSort(&a); // Рекурсивная сортировка подсписков.
MergeSort(&b);//Сортировка второй половины
*headRef = SortedMerge(a, b);//Вызов функции слияния}
If
((head
== NULL) || (head->next == NULL))
FrontBackSplit(head,
&a, &b);
*headRef
= SortedMerge(a, b);
MergeSort(&a);
MergeSort(&b);
Рисунок 18 - Блок-схема функции MergeSort
Вызов данной функции происходит при использование пользователем кнопки «Сортировать»:
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
pin_ptr<node*> pHoloce = &holoce;
MergeSort(pHoloce);
paintSp(holoce);
}
Функция atoi служит для преобразования переменной строчного типа в целочисленную переменную. Далее представлены ее код и блок-схема (рисунок 19):
int atoi( const char *c ) {
int value = 0;
while ( *c!=0 ) {
value *= 10;
value += (int) (*c-'0');
c++;
}
return value;
}
Рисунок 19 - Блок-схема функции atoi
Программа делится на функции так, что одна функция может вызывать другую при надобности (полный листинг программы смотреть в приложение).
3.5 Описание входных и выходных данных
Входными данными программы Tratata.cpp являются введенные с клавиатуры пользователем значения элементов списка.
Выходными данными программы Tratata.cpp являются:
графическое изображение списка в ходе дополнения элементов;
графическое изображение отсортированного списка.
4
ЭКСПЕРИМЕНТАЛЬНЫЙ РАЗДЕЛ
Тестирование
Тестирование показало корректность программы.
4.1 Тестирование А.
Данное тестирование проводится по представленному выше алгоритму (см. раздел 2.2). Неупорядоченный список (рисунок 20).
Рисунок 20 – Неупорядоченный список
Список после сортировки (рисунок 21).
Рисунок 21 – Результирующий упорядоченный список
4.2
Тестирование Б.
Происходит запуск программы, далее открывается диалоговое окно (рисунок 22).
Рисунок 22 – Окно приложения
В пустом текстовом поле следует ввести любое неотрицательное целое число (рисунок 23).
Рисунок 23 - Ввод первого элемента списка
После нажатия кнопки «Добавить», число будет добавлено в список, который сразу же отобразиться в форме (рисунок 24).
Рисунок 24 - Добавление первого элемента списка и его отображение
Можно продолжить вводить значения (рисунок 25).
Рисунок 25 - Ввод элемента
Следующее число также будет отображено в графическом изображение списка (рисунок 26).
Рисунок 26 - Добавление элемента в список и его отображение
Продолжение ввода чисел (рисунки 27-28).
Рисунок 27 - Добавление элемента в список и его отображение
Рисунок 28 - Добавление элемента в список и его отображение
Для сортировки полученного списка, следует нажать на кнопку «Сортировать», вследствие чего будет вызвана функция сортировки (рисунок 29).
Рисунок
29 - Сортировка полученного списка и
отображение результата
Так же далее происходит добавление элементов список и затем их сортировка (рисунки 30-32).
Рисунок 30 - Добавление элемента в список и его отображение
Рисунок 31 - Добавление элемента в список и его отображение
Рисунок 32 - Сортировка полученного списка и отображение результата