учебное пособие. Часть1. Информатика
.pdfУдаление узла производится еще пpоще (рис. 28): k = top;
top = top->link; delete k;
Рассмотрим пример, демонстрирующий удаление различных узлов стека (это более сложный процесс): из входной последовательности чисел построить стек, удалить из стека узлы, содержащие максимальное значение (рис. 29).
// Пример pr56
#include <cstdio> using namespace std;
int main()
{
struct node
{ char info; node *link; };
node *top, *k; char w;
top = NULL;
puts ( "введите число" ); scanf ( "%c", &w ); while ( !feof ( stdin ))
{
k = new node; k->link = top; k->info = w; top = k ;
printf ( "введите число\n" ); scanf ( " %c", &w );
}
/* Вывод построенного стека*/ k=top;
while ( k != NULL )
{
printf (" %c", k->info ); k = k->link;
}
//Поиск максимального значения k = top;
int max = top->info; while (k!=NULL)
{
281
top |
top |
info
link
info
link
info
link
info |
|
link |
|
|
info |
info |
link |
|
|
link |
|
.....
.....
info
link
NULL
Рис. 30.
info
link
NULL
Рис. 31.
if ( k->info>max ) max = k->info; k = k->link;
}
// Удаление узлов стека, содержащих максимальное значение k = top;
node *l = top;// Указатель на предыдущий узел while ( k != NULL )
{
if ( k->info == max) if ( k == top )
{ //Если максимальный в вершине стека top = k->link;
delete k;
282
k = top;
}
else
{ //ecли максимальный не веpшина l->link = k->link;
delete k;
k = l->link;
}
else
{ //если не максимальный l = k;
k = k->link;
}
}
puts ( "Стек после удаления максимального:" ); k = top;
while ( k != NULL )
{
printf ( " %c", k->info ); k = k->link;
}
return 0;
}
Следующий пример демонстрирует добавление узлов не только в вер- шину стека, но и в произвольное место (рис. 31). Построение стека из вход- ной последовательности символов и добавление узлов c символом ':' пеpед каждым знаком '=’.
//Пример pr56
#include <cstdio> using namespace std; int main()
struct node
{
char info; node *link;
};
{
node *top, *k; char w;
top = NULL;
puts ( "введите cимвол:" ); scanf( "%c", &w );
while (!feof (stdin ))
283
{
k = new node; k->link = top; k->info = w; top = k ;
printf ( "введите число\n" ); scanf ( " %c", &w );
}
k = top;
while ( k != NULL )
{
printf ( " %c", k->info ); k = k->link;
}
//Добавление узлов фактически после знака '=' k = top;
node *newnode; /* Поиск знаков '='
while ( k != NULL )
{
if ( k->info == '=' )
{
newnode = new node;// Добавление узла newnode->link = k->link;
k->link = newnode; newnode->info = ':';
}
k = k->link;
}
puts ( "после добавления узлов" ); k = top;
while ( k != NULL )
{
printf ( " %c", k->info ); k = k->link;
}
return 0;
}
Ещё одним способом организации простейшего линейного списка яв- ляется организация типа очередь (далее очередь). Организация очередей по- хожа на схему стека, но в очереди пришедший первым обслуживается пер- вым (рис. 32), т. е. это способ организации ожидания. Часто очередь описы- вают как структуру FIFO: first in - fist out. Доступ
284
к очереди осуществляется через две точки: в конец очереди и удалены из ее начала.
l
info |
info |
link |
link |
данные могут быть добавлены
r
..... |
info |
|
link
NULL
Рис. 32.
Следующая программа демонстрирует построение очереди из входной последовательности чисел.
//Пример pr57 #include <cstdio> using namespace std; int main()
{
struct node
{
int info; node *link; };
node *k, // Рабочий указатель
*l, *r; // Левый и правый указатели int w;
// Создание пеpвого узла puts ( "введите число" ); scanf ( "%d", &w );
k = new node; k->link = NULL;
k->info = w; l = r = k;
//Построение остальных узлов очереди printf ( "введите число" );
scanf ( " %d", &w ); while ( !feof ( stdin ))
{
k = new node; k->link = NULL; k->info = w;
285
r->link = k ;//добавление узла справа r = k;
printf ( "введите число\n" ); scanf(" %d",&w);
}
//Вывод содержимого очереди k = l;
while ( k != NULL )
{
printf ( "%c", k->info ); k = k->link;
}
return 0;
}
Добавление нового узла к очереди происходит справа (используется указатель r):
node *newnode; scanf ( " %c", &w ); newnode= new node;
newnode->link = NULL; newnode->info = w;
r->link = newnode ; // Добавление узла справа r = newnode;
Исключение узла из очереди происходит слева (используется указа- тель l):
k = l;
l = l->link; delete k;
Если к операторам формирования очереди добавить ещё один опера-
тор:
r->link=l;
то получится циклический список (рис. 33). При этом любой из указате- лей l или r может быть принят за "голову" списка.
286
l
info |
info |
link |
link |
.....
r
info
link
Рис. 33.
11.2. Двусвязные линейные списки
Для построения двусвязных списков используются структуры, имею- щие не менее двух полей, содержащих указатели на эту же структуру. На рис. 34 приведен линейный список с двумя связями. Наличие двух связей по- зволяет перемещаться по списку как слева направо, так и справа налево.
l
info
llink
rlink NULL
info |
info |
|
|
llink |
llink |
..... |
|
rlink |
rlink |
||
|
r
info
llink
rlink NULL
Рис. 34.
Следующая программа демонстрирует построение двусвязного списка из входной последовательности целых чисел, добавление узлов в список (рис. 35), удаление узлов из списка (рис. 36) .
287
l
info
llink
rlink NULL
info |
llink |
rlink |
info |
info |
llink |
llink |
rlink |
rlink |
|
r |
info |
|
... |
|
llink |
|
rlink |
NULL |
l
info |
llink |
rlink |
NULL
|
Рис. 35. |
|
|
|
|
|
r |
info |
info |
|
info |
llink |
llink |
..... |
llink |
|
|||
rlink |
rlink |
|
rlink |
|
|
|
NULL |
Рис. 36.
//Пример pr58 #include <cstdio> using namespace std; int main()
struct node //Описание узла
{
int g; //Информационное поле node *rlink,
*llink;// Поля для связи с другими узлами
};
/*____Функция вывода списка слева напpаво_____*/
288
void llist ( node *left )
{
node *k = left; while ( k != NULL )
{
printf ( "%d \n" ,k->g ); k = k->rlink;
}
}
/*_____Функция вывода списка спpава налево_____*/ void rlist ( node *right )
{
node *k = rigth; while ( k != NULL )
{
printf ( "%d \n ", k->g );
k = k->llink; |
|
} |
|
} |
|
void main () |
|
{ |
|
node *k, *q, |
// Рабочие указатели |
*left, *rigth; // Левый и правый указатели |
|
int w; |
// Буферная переменная |
// Создание пеpвого узла printf ( "введите число" ); scanf ( "%d", &w );
k = new node; // Выделение дин. памяти под узел k->g = w;//Заполнение полей узла
k->rlink = NULL;
k->llink = NULL; rigth = k;
q = k; // Указатель на предпоследний узел /*______Построение остальных узлов списка_______*/ printf ( "введите следующее число:" );
scanf ( "%d", &w ); while ( !feof ( stdin ))
{
k = new node; k->g = w;
k->rlink = q; //Связываем созданный узел с предыдущим q->llink = k; //Связываем предыдущий узел с созданным
289
q = k;
printf ( "введите следующее число:" ); scanf ( "%d", &w );
}
q->llink = NULL; left = q;
puts ( "Слева напpаво " ); llist ( left ); puts ( "Спpава налево" ); rlist ( right );
//Добавление после узла, содержащего положительное
//значение, узла, содержащего ноль (слева направо) node *newnode; // Указатель на новый узел
k = left;
while ( k !=NULL )
{
if ( k->g > 0 )
{
newnode = new node; newnode->g = 0; newnode->rlink = k->rlink; newnode->llink = k;
if ( k == right )
rigth = newnode;//Если добавляем после последнего else
k->rlink->llink = newnode; //Добавляем в середину k->rlink=newnode;
}
k = k->rlink;
}
puts ( "Вывод после добавления нулей" ); puts ( "Слева напpаво " ); llist ( left ); puts ( "Спpава налево" ); rlist ( rigth);
/*____________Удаление нулей_______________*/ node *l;//Указатель на предыдущий узел
l = k = left;
while ( k != NULL )
{
if ( k->g == 0 )
{
if ( k == left ) //Удаление самого левого
{
q = k;
left = k->rlink; left->llink = NULL;
290