
- •Введение
- •Теоретический раздел
- •Определение списка
- •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.1 Математическая постановка задачи
- •2.2 Описание входных и выходных данных
- •Программный раздел
- •3.1 Описание структуры программы и её основных частей
- •3.2 Описание функций составных частей и связей между ними
- •Экспериментальный раздел Тестирование
- •Заключение
- •Список использованных источников
2.2 Описание входных и выходных данных
Входными данными программы Tratata.cpp являются:
Введенные с клавиатуры пользователем значения элементов списка.
Выходными данными программы Tratata.cpp являются:
Графическое изображение списка в ходе дополнения элементов;
Графическое изображение отсортированного списка.
Программный раздел
3.1 Описание структуры программы и её основных частей
Программная компонента реализована в виде основной программы Tratata.cpp, написанной на языке C, в которой вызывается заголовочный файл Form1.h.
Общий порядок работы таков: компилятор Microsoft Visual Studio 2010 языка C компилирует программу Tratata.cpp; в ходе компиляции происходит вызов заголовочного файла Form1.h, затем обработка пользовательских параметров, чтение входных данных, подготовка входных данных для функции преобразования типов переменных atoi, её запуск с ожиданием завершения, чтение выходных данных функции atoi, запуск функций, с учетом выбора команд пользователем, которые представлены в виде кнопок в приложение Windows Forms, «Добавить» или «Сортировать», каждой кнопке соответствует свой набор команд. В ходе завершения работы функций происходит формирование окончательного результата и вывод его в форме в виде схематического изображения списка. Таким образом, пользователь взаимодействует с приложением Windows Forms, а все функции выполняются автоматически в файле Form1.h.
3.2 Описание функций составных частей и связей между ними
Программа реализует основную логику алгоритма сортировки слиянием, а также осуществляет ввод-вывод пользовательских и рабочих данных и интерфейс пользователя (вывод графических изображений). В ходе своей работы программа может использовать функции addnode, Length, FrontBackSplit, SortedMerge, MergeSort, atoi для выполнения ресурсоёмких вычислений или (в некоторых случаях) использовать ранее полученные результаты её работы.
Функция addnode выполняет операцию добавления элемента в список, для каждого нового элемента выделяется память, достаточная для его размещения, с помощью функции выделения динамической памяти malloc. Далее идет проверка того, удалось ли выделить запрашиваемое количество памяти. Это выполняется с помощью оператора if и условия (tnode != NULL). В случае выполнения , элемент будет добавлен, иначе нет. Вызов данной функции происходит при использование кнопки «Добавить». Далее представлен код самой кнопки, в которой используется описанная функция, код самой функции и ее блок-схема (рис.7):
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;
}
1
1
Рис.7. Блок-схема функции addnode.
Функция Length используется для определение длины списка на данный момент. Происходит это с использование цикла с предусловием while и переменной count, которая является счетчиком элементов списка, переход к следующему элементу осуществляется через указатель. В результате функция возвращает целое число – длину списка. Далее представлен код функции и блок-схема (рис.8):
int Length(struct node* head) //функция для определения длины списка
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
Рис.8. Блок-схема функции Length.
Функция FrontBackSplit для разбиения имеющего списка на подсписки использует описанную выше функцию Length. Так как в программе реализована работа алгоритма сортировки слиянием, необходима функция, в ходе выполнения которой имеющийся список будет разбиваться на подсписки. В функции используются операторы условия if, цикл с известным количеством повторений for и указатели frontRef, backRef, которые являются результатами выполнения функции (разбиения на подсписки). Ниже фрагмент программы, на котором представлена реализация функции, и ее блок-схема (рис.9):
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;
}
}
Рис.9. Блок-схема функции FrontBackSplit.
Функция SortedMerge обеспечивает слияние упорядоченных подсписков в один результирующий с учетом отношения порядка. Происходит работа с указателями, операторами условия, так как функция является рекурсивной, то в ходе ее выполнения функция вызывает сама себя. В последующем SortedMerge будет использоваться в другой функции, MergeSort. Ниже представлен код функции и ее блок-схема (рис.10):
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);
}
Рис.10. Блок-схема функции SortedMerge
Основная функция программы – это функция MergeSort, она осуществляет рекурсивную сортировку подсписков и их слияние в результирующий список благодаря функции SortedMerge, которую она вызывает, а также функция FrontBackSplit для разбиения списка на подсписки. В функции использовались указатели, операторы условия. В ходе выполнения происходит проверка длины списка, если список пуст или состоит из одного элемента, работа функции прекращается. Ниже представлен код самой функции и ее блок-схема (рис.11):
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);//Вызов функции слияния
}
1
1
Рис.11. Блок-схема функции MergeSort.
Вызов данной функции происходит при использование пользователем кнопки «Сортировать»:
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
pin_ptr<node*> pHoloce = &holoce;
MergeSort(pHoloce);
paintSp(holoce);
}
Функция atoi служит для преобразования переменной строчного типа в целочисленную переменную. Далее представлены ее код и блок-схема (рис.12):
int atoi( const char *c ) {
int value = 0;
while ( *c!=0 ) {
value *= 10;
value += (int) (*c-'0');
c++;
}
return value;
}
value
*= 10; value
+= (int)
(*c-'0'); c++;
while
( *c!=0 )
int
value = 0;
return
value;
Рис.12. Блок-схема функции atoi.
Программа делится на функции так, что одна функция может вызывать другую при надобности.
3.3 Сведения о языке программирования
Данная программа была выполнена на языке программирования высокого уровня С с использованием компилятора Microsoft Visual Studio 2010 в среде операционной системы Windows 8.
3.4 Листинг программы
3.4.1 Листинг Tratata.cpp
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Включение визуальных эффектов Windows XP до создания каких-либо элементов управления
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Создание главного окна и его запуск
Application::Run(gcnew Form1());
return 0;
}
3.4.2 Листинг заголовочного файла Form1.h
#pragma once
#include "stdio.h"
#include "math.h"
#include <stdlib.h>
#include <vcclr.h>
using namespace System::Runtime::InteropServices;
struct node {
int number;
struct node *next;
};
namespace Tratata {
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>
/// Сводка для Form1
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: добавьте код конструктора
//
}
protected:
/// <summary>
/// Освободить все используемые ресурсы.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::Label^ Число;
protected:
protected:
private: System::Windows::Forms::TextBox^ textBox1;
private: System::Windows::Forms::Button^ Добавить;
private: System::Windows::Forms::PictureBox^ pictureBox1;
private: System::Windows::Forms::Button^ button2;
private: System::Windows::Forms::Label^ label1;
private: System::Windows::Forms::Label^ label2;
protected:
private:
/// <summary>
/// Требуется переменная конструктора.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Обязательный метод для поддержки конструктора - не изменяйте
/// содержимое данного метода при помощи редактора кода.
/// </summary>
void InitializeComponent(void)
{
this->Число = (gcnew System::Windows::Forms::Label());
this->textBox1 = (gcnew System::Windows::Forms::TextBox());
this->Добавить = (gcnew System::Windows::Forms::Button());
this->pictureBox1 = (gcnew System::Windows::Forms::PictureBox());
this->button2 = (gcnew System::Windows::Forms::Button());
this->label1 = (gcnew System::Windows::Forms::Label());
this->label2 = (gcnew System::Windows::Forms::Label());
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->pictureBox1))->BeginInit();
this->SuspendLayout();
//
// Число
//
this->Число->AutoSize = true;
this->Число->Location = System::Drawing::Point(26, 15);
this->Число->Name = L"Число";
this->Число->Size = System::Drawing::Size(84, 13);
this->Число->TabIndex = 0;
this->Число->Text = L"Введите число ";
this->Число->Click += gcnew System::EventHandler(this, &Form1::label1_Click);
//
// textBox1
//
this->textBox1->Location = System::Drawing::Point(127, 12);
this->textBox1->Name = L"textBox1";
this->textBox1->Size = System::Drawing::Size(62, 20);
this->textBox1->TabIndex = 1;
this->textBox1->TextChanged += gcnew System::EventHandler(this, &Form1::textBox1_TextChanged);
//
// Добавить
//
this->Добавить->Location = System::Drawing::Point(214, 12);
this->Добавить->Name = L"Добавить";
this->Добавить->Size = System::Drawing::Size(75, 23);
this->Добавить->TabIndex = 2;
this->Добавить->Text = L"Добавить";
this->Добавить->UseVisualStyleBackColor = true;
this->Добавить->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//
// pictureBox1
//
this->pictureBox1->Location = System::Drawing::Point(12, 67);
this->pictureBox1->Name = L"pictureBox1";
this->pictureBox1->Size = System::Drawing::Size(985, 177);
this->pictureBox1->TabIndex = 3;
this->pictureBox1->TabStop = false;
//
// button2
//
this->button2->Location = System::Drawing::Point(311, 12);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(88, 23);
this->button2->TabIndex = 4;
this->button2->Text = L"Сортировать";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
//
// label1
//
this->label1->AutoSize = true;
this->label1->Location = System::Drawing::Point(514, 15);
this->label1->Name = L"label1";
this->label1->Size = System::Drawing::Size(193, 13);
this->label1->TabIndex = 5;
this->label1->Text = L"Фрышкина Екатерина. Группа Б-662";
//
// label2
//
this->label2->AutoSize = true;
this->label2->Location = System::Drawing::Point(514, 38);
this->label2->Name = L"label2";
this->label2->Size = System::Drawing::Size(320, 13);
this->label2->TabIndex = 6;
this->label2->Text = L"Реализация сортировки слиянием с использованием списка";
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(1009, 301);
this->Controls->Add(this->label2);
this->Controls->Add(this->label1);
this->Controls->Add(this->button2);
this->Controls->Add(this->pictureBox1);
this->Controls->Add(this->Добавить);
this->Controls->Add(this->textBox1);
this->Controls->Add(this->Число);
this->Name = L"Form1";
this->Text = L"Сортировка слиянием списка";
this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
(cli::safe_cast<System::ComponentModel::ISupportInitialize^ >(this->pictureBox1))->EndInit();
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
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;
}
int Length(struct node* head)
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
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;
}
}
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);
}
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);//Вызов функции слияния.
}
static struct node* holoce=NULL;//голова списка
void paintSp(struct node* head){
System::Drawing::Graphics^ formGraphics;
formGraphics = pictureBox1->CreateGraphics();
//создание экземпляра пера
System::Drawing::Pen^ myPen =
gcnew System::Drawing::Pen(System::Drawing::Color::Blue);
//cоздание экземпляра кисти
System::Drawing::SolidBrush^ myBrush=
gcnew SolidBrush(System::Drawing::Color::White);
struct node* now=head;
int step = 30;
formGraphics->FillRectangle(myBrush, 0, 0, 1000, 200);
myBrush = gcnew SolidBrush(System::Drawing::Color::Blue);
int y = 20;
int x = 10;
formGraphics->DrawEllipse(myPen, x-10, y-10, x+15, y+10);
x=x+15;
while(now!=NULL){
formGraphics->DrawLine(myPen, x, y, x+step, y);
x+=step;
formGraphics->DrawRectangle(myPen, x, y-10, 50, 30);
System::Drawing::Font^ drawFont =
gcnew System::Drawing::Font("Arial", 11);
formGraphics->DrawString(""+now->number, drawFont, myBrush, x+5,y);
x=x+50;
now=now->next;
}
}
int atoi( const char *c ) {
int value = 0;
while ( *c!=0 ) {
value *= 10;
value += (int) (*c-'0');
c++;
}
return value;
}
private: System::Void label1_Click(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
pin_ptr<node*> pHoloce = &holoce;
MergeSort(pHoloce);//Вызов функции сортировки слиянием.
paintSp(holoce);
}
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);
}
private: System::Void textBox1_TextChanged(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void textBox2_TextChanged(System::Object^ sender, System::EventArgs^ e) {
}
};
}