книги / Проектирование программ и программирование на C++. Структурное программирование
.pdf//использование объединений
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 ; //в е р н у т ь |
первый |
элем ен т |
списка |