Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

МЕТОДИЧКА_С++_Ч2

.pdf
Скачиваний:
49
Добавлен:
15.02.2015
Размер:
876 Кб
Скачать

fin.read(buf, len);

 

// 5

buf[len]

= '\0';.

 

0; //6

long n =

0, i

= 0, j=

while(buf[i])

{

//

7

if(buf[i]=='?'){

 

//8

for ( j = n; j <= i; j++) cout << buf[j]; n = і + 1;

}

if ( buf[i] =='.' || buf[i] =='!' ) n = i+ 1; i++; }

}

fin.close(); // 9 cout << endl;

return 0;

}

Варіант рішення цієї ж задачі з використанням замість потокових класів

бібліотечних функцій, успадкованих з мови С.

#include <stdio.h>

 

 

 

int main(){

// 1

 

 

FILE *fin;

// 2

 

fin = fopen("text.txt","r" );

 

if (!fin) {

 

 

 

puts("Помилка відкриття файлу");

 

 

return 1; }

 

// 3

 

fseek(fin, 0, SEEK_END);

 

long len= ftell(fin);

 

//4

 

char

*buf = new char [len + 1];

// 5

 

const int l_block = 1024;

 

int num_block= len / l_block;

// 6

 

fseek(fin,0, SEEK_SET);

 

// 7

// 8

fread(buf, l_block, num_block + 1,

fin);

buf[len] = '\0';

 

 

 

long n = 0, і= 0, j= 0;

 

 

 

while(buf[i]) { if( buf[1] =='?'){

 

 

for ( j = n; j <= 1; j++) putcnar(buf[j]); n = і + 1;

}

if ( buf[i]=='.' || buf[i]=='!' )n=i + 1; i++;

}

fclose(fin);

printf("\n"); return 0; }

61

Звіт

1.Тема практичної роботи.

2.Мета практичної роботи.

3.Умови завдання.

4.Намалюваний алгоритм у вигляді блок-схеми програми.

5.Текст програми.

6.Відповіді на контрольні питання.

7.Висновки.

Контрольні питання

1.Що таке потік в мові програмування С++?

2.Які потоки автоматично відкриваються системою з початком будь-якої програми в мові С++?

3.Який формат оголошення вказівника на потік? Наведіть приклад.

4.Які режими відкриття потоку і відповідні ім параметри ви знаєте?

5.Які функції використовуються для відкриття/закриття потоку в мові С++? Їх формати.

6.Яка функція використовується для запису символів в файл (для зчитування символів з файлу)?

7.Які функції використовуються для запису цілих чисел в файл і читання цілих чисел з файлу?

8.Які функції використовуються для запису блоків даних в потік і читання блоків даних з потоку?

9.Які функції використовуються для форматного виведення з файлу і форматного введення в файл?

62

Практична робота №12

Тема: Програмування з використанням динамічних

структур даних в мові С++

Мета роботи: Оволодіння навиками алгоритмізації і програмування з використанням динамічних структур даних, навиками створення та використання лінійних списків.

Теоретичні відомості

Загальні відомості про динамічні структури даних.

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

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

полями яких є масиви і структури.

Пам'ять під дані виділяється або на етапі компіляції (в цьому випадку необхідний об'єм повинен бути відомий до початку виконання програми, тобто заданий у вигляді константи), або під час виконання програми за допомогою операції new або функції mallос (необхідний об'єм повинен бути відомий до розподілу пам'яті). У обох випадках виділяється безперервна ділянка пам'яті.

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

Динамічна структура може займати несуміжні ділянки оперативної пам'яті.

Динамічні структури широко застосовують і для ефективнішої роботи з даними,

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

63

впорядковування динамічних структур не вимагає перестановки елементів, а

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

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

Елемент будь-якої динамічної структури даних є структурою (у сенсі struct),

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

основного, складеного або типу покажчик. Опис простого елементу (компоненти,

вузла) виглядає таким чином:

struct Node{

Data d; // тип даних Data повинен бути визначений

раніше

Node *р;

};

Розглянемо реалізацію основних операцій з динамічними структурами даних.

Різновиди лінійних списків.

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

однонаправленим (однозв’язним). Якщо додати в кожен елемент друге посилання — на попередній елемент, вийде двонаправлений список (двозв’язний), якщо останній елемент зв'язати покажчиком з першим, вийде кільцевий список.

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

якщо створюється лінійний список із записів, що містять прізвище, рік народження,

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

наприклад, ветеранів праці ключем буде стаж. Ключі різних елементів списку можуть співпадати.

64

Операції над списками.

Над списками можна виконувати наступні операції:

початкове формування списку (створення першого елементу);

додавання елементу в кінець списку;

читання елементу із заданим ключем;

вставка елементу в задане місце списку (до або після елементу із заданим ключем);

видалення елементу із заданим ключем;

впорядковування списку по ключу.

Розглянемо двонаправлений лінійний список. Для формування списку і роботи з ним потрібно мати принаймні один покажчик — на початок списку. Зручно завести ще один покажчик — на кінець списку. Для простоти допустимо, що список складається з цілих чисел, тобто опис елементу списку виглядає таким чином:

struct Node{

int d;

Node *next;

Node *prev;

};

Розглянемо докладніше функцію видалення елементу із списку remove (Приклад

12.1). Її параметрами є покажчики на початок і кінець списку і ключ елементу, який потрібно видалити. У рядку 1 виділяється пам'ять під локальний покажчик pkey,

якому привласнюється результат виконання функції знаходження елементу по ключу fіnd. Ця функція повертає покажчик на елемент у разі успішного пошуку і 0,

якщо елементу з таким ключем в списку немає. Якщо pkey набуває ненульового значення, умову в операторові іf стає істинним (елемент існує), і управління передається операторові 2, якщо немає — виконується повернення з функції із значенням false (оператор 6).

65

Видалення із списку відбувається по-різному залежно від того, знаходиться елемент на початку списку, в середині або в кінці. У операторові 2 перевіряється, чи знаходиться елемент, що видаляється, на початку списку — в цьому випадку слід скоректувати покажчик pbeg на початок списку так, щоб він указував на наступний елемент в списку, адреса якого знаходиться в полі next першого елементу. Новий початковий елемент списку повинен мати в своєму полі покажчика на попередній елемент значення 0.

Якщо видаляємий елемент знаходиться в кінці списку (оператор 3), потрібно змістити покажчик pend кінця списку на попередній елемент, адресу якого можна отримати з поля prev останнього елементу. Крім того, потрібно обнулити для нового останнього елементу покажчик на наступний елемент. Якщо видалення походить з середини списку, то єдине, що треба зробити, — забезпечити двосторонній зв'язок попереднього і наступного елементів. Після коректування покажчиків пам'ять з-під елементу звільняється, і функція повертає значення true.

Робота функції вставки елементу в список проілюстрована на рис. 12.1.

Номери біля стрілок відповідають номерам операторів в коментарях.

Сортування зв'язаного списку полягає в зміні зв'язків між елементами.

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

Рисунок 12.1. Вставка элемента в список Нижче приведена функція формування впорядкованого списку (передбачається,

що перший елемент існує):

66

void add_sort(Node **pbeg, Node **pend, int d){ Node *pv = new Node; // добавляемый элемент pv->d = d;

Node * pt = *pbeg;

while (pt){ // просмотр списка

if (d < pt->d){ // занести перед текущим элементом (pt) pv->next = pt;

if (pt == *pbeg){ // в начало списка pv->prev = 0;

*pbeg = pv;}

else{ // в середину списка

(pt->prev)->next = pv;

pv->prev = pt->prev;} pt->prev = pv; return;

}

pt = pt->next;

}

pv->next =0; //в конец списка pv->prev = *pend; (*pend)->next = pv;

*pend = pv;

}

Послідовність виконання роботи

1.Уважно ознайомитися з теоретичним матеріалом щодо виконання практичної роботи.

2.Вивчити :

формат опису простого елементу (компоненти, вузла) ;

різновиди лінійних списків;

операції над лінійними списками.

3.Набрати програму з Прикладу 12.1.

67

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

5.Оформити звіт по практичній роботі. Звіт повинен містити: тему, мету,

постановку задачі, текст програми і результати роботи програми.

Завдання до практичної роботи

Набрати навадену нижче програму, яка формує список з 5 чисел, додає число в список, видаляє число із списку і виводить список на екран. Вказівник на початок списку позначений pbeg, на кінець списку — pend, допоміжні вказівники — pv і pkey.

Приклад 12.1

#include <iostream.h> #include <conio.h> struct Node{

int d; Node *next; Node *prev; };

//------------------------

Node *first(int d);

void add(Node **pend, int d);

Node *find(Node * const pbeg, int i);

bool remove(Node **pbeg, Node **pend, int key);

Node *insert(Node * const pbeg, Node **pend, int key, int d); //-------------------------

int main(){

Node *pbeg = first(1); // Formuvannya pershogo elementa spiska

Node *pend = pbeg;// Spisok zakanchuetsya

//Dodavannya v kinrc spisku chotiryoh elementiv 2, 3, 4, 5: for (int i = 2; i<6; i++)add(&pend, i);

//Vstavka elementiv 200 pislya elementu 2:

insert(pbeg, &pend, 2, 200);

// Vidalennya elementu 5:

if(!remove

(&pbeg,

&pend, 5))cout << "ne znaydeno";

Node

*pv =

pbeg;

 

 

while (pv){

//

vivedennya spisku na ekran

cout

<< pv->d <<

'

';

pv =

pv->next;

 

 

68

}

getch(); return 0;

}

//Formuvannya pershogo elementu Node * first(int d){

Node *pv = new Node; pv->d = d;

pv->next = 0; pv->prev = 0; return pv;

}

//Dodavannya v kinec spisku void add(Node **pend, int d){ Node *pv = new Node;

pv->d = d; pv->next = 0; pv->prev = *pend; (*pend)->next = pv; *pend = pv;

}

//Poshuk elementa po klyuchu

Node * find(Node * const pbeg, int d){

Node *pv = pbeg; while (pv){

if(pv->d == d)break; pv = pv->next;

}

return pv;

}

// Vidalennya elementa

bool remove(Node **pbeg, Node **pend, int key){

if(Node

*pkey

= find(*pbeg, key)){

// 1

if (pkey == *pbeg){

// 2

*pbeg =

(*pbeg)->next;

 

(*pbeg)->prev

=0;}

 

else if

(pkey

== *pend){

// 3

*pend =

(*pend)->prev;

 

(*pend)->next

= 0;} else{

// 4

(pkey->prev)->next = pkey->next;

 

(pkey->next)->prev = pkey->prev;}

 

delete pkey;

 

 

69

return

true;

// 5

}

 

 

return

false;

// 6

}

 

 

// Vstavka elementa

 

Node *

insert(Node * const pbeg, Node **pend, int key, int

d){

if(Node *pkey = find(pbeg, key)){ Node *pv = new Node;

pv->d = d;

//1 - vstanovlennya zvyazku novogo vuzla z nastupnim pv->next = pkey->next;

//2 - vstanovlennya zvyazku novogo vuzla z poperednim pv->prev = pkey;

//3 - vstanovlennya zvyazku poperednyogo vuzla z novim pkey->next = pv;

//4 - vstanovlennya zvyazku nastupnogo vuzla z novim: if( pkey != *pend) (pv->next)->prev = pv;

//onovlennya vkazivnika na kinec spiska,

//yaksho vuzol vstavlyaetsya v kinec:

else *pend = pv;

return pv;

}

return 0; }

Результат роботи програми: 1 2 200 3 4

Контрольні питання

1.Що називають динамічними структурами даних?

2.Які динамічні структури даних найчастіше використовуються в програмуванні?

3.Які різновиди лінійних списків вам відомі?

4.Які операції можна виконувати над списками?

5.Як в програмі на С++ описується елементу списку?

6.В чому полягає алгоритм роботи функції видалення елементу із списку?

7.В чому полягає алгоритм роботи функції вставки елементу в список?

70