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

книги / Проектирование программ и программирование на C++. Структурное программирование

.pdf
Скачиваний:
4
Добавлен:
12.11.2023
Размер:
3.86 Mб
Скачать

//использование объединений

enum paytype{CARD,CHECK}; //тип оплаты struct

{

/*поле, которое определяет, с каким полем объ­

единения будет выполняться работа*/ paytype ptype;

union

{

c h a r c a r d [2 5 ]; lo n g c h e c k ;

};

} info;

switch (infо .ptype)

{

case CARD:cout«"\nOrLnaTa по карте: "«info, card; break;

case CHECK:со и « < "\п О п л ата чеком: " « i n f o , check; b reak ;

}

19. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ

Во многих задачах требуется использовать данные, у которых конфигурация, размеры и состав могут меняться в процессе выпол­ нения программы. Для их представления используют динамические информационные структуры. К таким структурам относят:

-линейные списки;

-стеки;

-очереди;

-бинарные деревья.

Они отличаются способом связи отдельных элементов и допус­ тимыми операциями. Динамическая структура может занимать не­ смежные участки динамической памяти.

Наиболее простой динамической структурой является линейный однонаправленный список, элементами которого служат объекты структурного типа (рис. 15).

Beg - начало списка

Рис. 15. Линейный однонаправленный список

Описание простейшего элемента такого списка выглядит сле­ дующим образом:

struct имя_типа

{

информационное поле; адресное поле;

}; - информационное поле - это поле любого, ранее объявленного

или стандартного, типа; - адресное поле - это указатель на объект того же типа, что

и определяемая структура, в него записывается адрес следующего элемента списка.

Информационных полей может быть несколько.

//пример 1

 

 

struct

point

 

 

{

 

 

поле

int key; //информационное

point*

next;

//адресное

поле

};

 

 

 

//пример 2

 

 

struct

person

 

 

{

 

//информационное поле

char* name;

int age; //информационное

поле

person*

next;

//адресное

поле

};

Каждый элемент списка содержит ключ, который идентифици­ рует этот элемент. Ключ обычно бывает либо целым числом (при­ мер 1), либо строкой (пример 2).

Над списками можно выполнять следующие операции:

-начальное формирование списка (создание первого элемента);

-добавление элемента в конец списка;

-добавление элемента в начало списка;

-поиск элемента с заданным ключом;

-удаление элемента с заданным ключом;

-удаление элемента с заданным номером;

-добавление элемента с заданным номером и т.д.

Рассмотрим основные операции над списком из примера 1.

19.1. Создание элемента списка

Каждый элемент списка содержит как минимум два поля: ин­ формационное и адресное. Для создания одного элемента необходи­ мо выделить под него память и заполнить поля элемента. Значение адресного поля можно ввести с клавиатуры, в адресное поле записать нулевое значение.

#include <iostream.h>

//описание структуры

struct point

{

int key;

//информационное

поле

point* next;

//адресное

поле

};

//создание элемента point* make_point()

{

point*p=new(point);//выделить память под

//элемент списка cout«"\nEnter the key";

cin»p->key;//заполнить информационное поле p->next=0;//сформировать адресное поле

return р;//вернуть указатель на созданный элемент

}

19.2. Создание списка из п элементов

Для того чтобы создать список из п элементов, нужно создать первый элемент с помощью рассмотренной выше функции make_point (), а затем добавить в список оставшиеся (п - 1) эле­ менты. Добавление может осуществляться либо в начало списка, ли­ бо в конец списка. При добавлении элемента в начало списка элемен­ ты списка будут располагаться в порядке, обратном тому, в котором элементы вводились, так как тот элемент, который был введен пер­ вым, в списке окажется последним.

Сформирование списка из п элементов путем до­ бавления элементов в начало списка*/

point* make_list(int n)

{

point* beg=make_point();//сформировать первый //элемент

point*r;//вспомогательная переменная для

//добавления

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

{

//сформировать следующий

r=make_point();

//элемент

 

//добавление в начало списка r->next=beg; //сформировать

//адресное поле

b e g = r;

//и з м е н и т ь

а д р е с п ер в о го

//э л е м е н т а сп и ска

 

 

}

 

 

r e t u r n b e g ;

//в е р н у т ь а д р е с

н а ч а л а сп и ска

}

Можно добавлять элементы не в начало, а в конец списка, тогда

порядок элементов не изменится.

 

 

 

 

 

/С ф ормирование

сп и ска и з

п эл ем ен то в

п утем д о ­

б авлен и я

эл ем ен то в

в

конец с п и с к а * /

 

 

p o in t* m a k e _ l i s t ( i n t n)

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

lf(n = = 0 )

r e t u r n

0 ; //с п и с о к

п у сто й

 

 

p o in t*

b e g = m a k e _ p o in t( ) ; //с ф о р м и р о в а т ь

первый

//э л е м е н т

 

 

 

 

 

 

 

 

 

 

 

 

i f (n==l)

r e t u r n

b e g ; //с п и с о к

и з одного

элем ен та

p o i n t * r ,

 

//н о в ы й

 

эл ем ен т

сп и ска

 

 

//у к а з а т е л ь

д ля

х р ан ен и я

а д р е с а п о с л е д н е го

//э л е м е н т а

сп и ска

 

 

 

 

 

 

 

 

*q;

 

 

 

 

 

 

 

 

 

 

 

 

q = b e g ;//п о с т а в и л и

 

у к а з а т е л ь q

на первый

элем ент

f o r ( i n t

 

i = l ;

i< n ;i+ + )

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

r= m a k e _ p o in t( ) ;

 

 

 

//с ф о р м и р о в ал и следующий

//э л е м е н т

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//д о б а в л е н и е

в кон ец

сп и ск а

 

 

//эл е м е н т о м

 

q - > n e x t= r ;

/ / с в я з а л и

сп и со к

с

новым

 

 

 

 

 

 

 

 

 

 

 

 

 

 

q = r;

//и з м е н и т ь

а д р е с п о сл ед н его

//э л е м е н т а

сп и ска

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

r e t u r n

b e g ;

//в е р н у т ь

а д р е с н ач ал а

сп и ска

19.3. Перебор элементов списка

Чтобы перебрать элементы списка, нужно встать на первый эле­ мент p=beg и переходить от одного элемента к следующему, исполь­ зуя адресное поле next: p = p -> n e x t, до тех пор пока список не закон­ чится, т.е. р не приобретет нулевое значение. При обходе выполняется

обработка ключевого поля списка. Рассмотрим перебор элементов спи

ска на примере функции печати.

 

 

 

 

v o id

p r i n t _ l i s t ( p o i n t * b e g ) //п е ч а т ь

сп и ска

{

 

 

 

 

 

 

p o in t* p = b e g ;//в с т а л и

на н ач ал о

сп и ска

//п р о в е р к а

нали чи я эл ем ен то в

в

сп и ске

i f

(!р )

{c o u t< < " \n T h e

l i s t

i s

e m p ty !" ;

r e t u r n ; }

 

 

 

 

 

 

w h ile ( p ) //п о к а значение

p не стан ет равно нулю

{

 

 

 

 

 

 

co u t< < p -> k ey < < " " ; //в ы в о д

клю чевого поля

p = p - > n e x t;//п е р е х о д к

следующему

элем ен ту

//с п и с к а

 

 

 

 

 

 

}

 

 

 

 

 

 

19.4. Удаление элемента с заданным номером

Чтобы удалить элемент с заданным номером (например, с номе­ ром к), нужно поставить указатель на элемент с номером k - I и изменить его адресное поле, присвоив ему значение адреса элемен­ та с номером к + 1. Затем элемент с номером к удаляется с помощью функции d e l e t e (рис. 16).

Инф ормационное Адресное

Beg - начало списка

Рис. 16. Удаление элемента из списка

/ /У даление и з однонаправленного списка элемента / / с номером к

p o i n t * d e l _ p o i n t ( p o i n t * b e g , i n t к)

{

/^ п о с т а в и т ь всп о м о гательн у ю переменную на на­ ч ал о с п и с к а * /

p o in t* p = b e g ;

 

 

 

 

 

 

 

p o i n t

* r ;

 

//в с п о м о г а т е л ь н а я п ерем ен ная

// д л я

у д ал ен и я

 

 

 

 

 

 

 

 

i n t i= 0 ;

 

//с ч е т ч и к

элем ен то в в

сп и ске

 

if(k = = 0 )

 

//у д а л и т ь

первый

элем ен т

 

 

{

 

b e g = p - > n e x t;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

d e l e t e

р ;

 

//у д а л и т ь

элем ен т

/ / и з

сп и ска

 

 

 

 

 

 

 

 

 

 

 

 

r e t u r n

b e g ;

//в е р н у т ь

ад р ес

//п е р в о г о

эл ем ен та

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

w h i l e ( р ) //п о к а

н ет

конца

сп и ска

 

 

{

 

 

 

 

 

 

 

 

 

/ * дошли до

эл ем ен та с

номером

к - 1 ,

чтобы поме­

н ять

е го

поле

n e x t* /

 

 

 

 

 

 

i f ( i = = k - l )

 

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

/^ п о с т а в и т ь

г

на

удаляемы й

эл е м ен т * /

r = p - > n e x t;

 

 

 

 

 

 

 

 

i f

(г)

/ / е с л и

р

не последний

элем ен т

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

p - > n e x t= r - > n e x t;

//и ск л ю ч и ть г

/ / и з

сп и ска

 

 

 

 

 

 

 

 

 

 

 

 

d e l e t e

г ;

 

//у д а л и т ь

элем ен т

/ / и з

сп и ска

 

 

 

 

 

 

 

 

}

/* е с л и р - последний эл ем ен т, то в поле n e x t п рисвои ть О*/

 

e l s e p -> n e x t= 0 ;

 

}

 

 

p = p - > n e x t;

//п е р е х о д к следующему

элем ен ту

i+ + ;

//у в е л и ч и т ь

сч етч и к

//э л е м е н т о в

}

r e t u r n b e g ; //в е р н у т ь а д р е с п ер в о го элем ен та

}

Удаление элемента с заданным ключом осуществляется анало­ гично, но вместо условия

if(i==k-l) //проверка номера

нужно использовать условие:

if (p->next->key==KEY)//проверка ключа,

где KEY - заданный ключ. Ключ KEY передается как параметр функ­ ции удаления.

19.5. Добавление элемента с заданным номером

Для добавления в список элемента с номером к нужно поставить указатель на элемент с номером k - 1. Затем нужно создать новый элемент и поменять значения адресных полей таким образом, чтобы адресное поле нового элемента содержало адрес элемента с номером к, а адресное поле к - 1 элемента - адрес нового элемента (рис. 17).

Информационное Адресное

, „

пппо

к-и элемент списка

Новый элемент

Рис. 17. Добавление элемента с номером к

point* add_elem(point*beg, int NOM)

{

point*p=make_point() ;//создание нового

//элемента

if (NOM==0)//добавление первого

//элемента

{

p->next=beg;//связываем новый элемент

//со списком

beg=p;//меняем адрес beg return beg;

}

point*r=beg;//указатель для перехода

//на нужный номер

/*проходим по списку до элемента с номером N0M-1

или до конца списка, если такого элемента нет*/ for(int i=0; i<NOM-l&& r!=0;i++)

r=r->next;

//если элемента с указанным номером в списке нет if (1г)

{

cout«"\nNot such NOM!"; //сообщение об ошибке return beg;

}

p->next=r->next;//связываем новый элемент со //списком

//связываем элемент с номером N0M-1 с новым //элементом

r->next=p; return beg;

19.6. Двунаправленные списки

Двунаправленный список имеет два адресных поля, которые указывают на следующий элемент списка и на предыдущий, поэтому двигаться по такому списку можно как слева направо, так и справа налево (рис. 18).

pred key next

Рис. 18. Двунаправленный список

//пример описания двунаправленного списка struct point //описание структуры

{

int key;

//ключевое поле

//адресные

поля

point*

pred,//адрес предыдущего элемента

*next;

//

адрес следующего элемента

};

Ниже рассматривается программа, которая создает двуна­ правленный список, выполняет удаление элемента с заданным номером, добавление элемента с заданным номером и печать по­

лученных списков

 

 

 

 

 

 

 

 

 

 

 

#in c lu d e c io s tr e a m .h >

 

 

 

 

 

 

 

 

s t r u c t

p o i n t

//о п и с а н и е

стр у к ту р ы

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

i n t

k ey ;

 

//к л ю ч е в о е

поле

 

 

 

 

 

p o in t*

p r e d ,* n e x t ;

 

 

 

//а д р е с н ы е

поля

 

};

 

 

 

 

 

 

 

 

 

 

 

 

 

//ф о р м и р о в а н и е

сп и ск а

 

 

 

 

 

 

 

 

p o i n t * m a k e _ l i s t ()

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

i n t

п ;

 

 

//к о л и ч е с т в о

эл ем ен то в

списка

c o u t « " n - ? " ;

 

 

 

 

 

 

 

 

 

 

c i n » n ;

 

 

 

 

 

 

 

 

 

 

 

 

 

p o in t* p , * r , * b eg ;

 

 

 

 

 

 

 

 

p=new

( p o i n t ) ;

/ / с о з д а т ь

первый

элемент

/* за п о м н и т ь

а д р е с в

перем енную

b e g ,

в

которой

х р а н и т с я н ач ал о с п и с к а * /

 

 

 

 

 

 

 

 

b eg = p ;

 

 

 

 

 

 

 

 

 

 

 

 

c o u t « " k e y - ? ,f;

 

 

 

 

 

 

 

 

 

c in > > p - > k e y ;

//з а п о л н и т ь

клю чевое

поле

 

p - > p r e d = 0 ;p - > n e x t= 0 ;//за п о м н и т ь

адресные

поля

//д о б а в и т ь

элем ен ты

в кон ец сп и ска

 

 

 

f o r ( i n t i = l ; i < n ; i + + )

 

 

 

 

 

 

 

 

 

 

r = n e w ( p o in t) ;

 

 

//н о в ы й

элем ент

 

 

 

c o u t< < " k e y - ? " ;

 

 

 

 

 

 

 

 

c i n » r - > k e y ;

//а д р е с н о е

поле

 

 

 

 

 

p - > n e x t= r ;

/ / с в я з а т ь

н ач ал о

сп и ска

с г

 

r - > p r e d = p ;

/ / с в я з а т ь

г

с началом

списка

 

r-> n e x t= 0 ;

//о б н у л и ть

последнее

адресное

поле

р = г ; //п е р е д в и н у т ь

р

на

последний

элемент

//с п и с к а

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

r e t u r n

b e g ; //в е р н у т ь

первый

элем ен т

списка

Соседние файлы в папке книги