Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть 1.doc
Скачиваний:
133
Добавлен:
24.09.2019
Размер:
6.98 Mб
Скачать

3.1.2. Реализация иерархических списков

В разделе 2.6. приводилась рекурсивная реализация линейных списков. Для иерархических списков можно выполнить аналогичную реализацию, но для этого потребуется несколько усложнить внутреннюю структуру данных. Поскольку каждый элемент может быть или значением базового типа, или указателем на список, наилучшим решением для языка С++ является использование типа union (объединение), которое позволяет использовать одну и ту же область памяти для хранения данных разных типов (в нашем случае базовый тип и тип указатель). Для того, чтобы отличать атомы от указателей на список, для каждого элемента вводим дополнительное поле логического типа, в котором будем хранить признак, является ли данное поле атомом (без него не обойтись). Таким образом, каждый элемент будет являться структурой (struct), состоящей из двух частей — признака атомарности (тип bool) и непосредственно определения элемента (тип union).

Заметим, что в языке Pascal для реализации иерархического списка удобно использовать записи с вариантами (case внутри определения record - аналог union).

Листинг 3.1 содержит реализацию базовых функций, определенных для иерархического списка, и некоторых дополнительных.

Листинг 3.1.

#include <iostream.h>

typedef int type_of_data; //тип может быть любым

struct list

{ bool atomic; // показывает, является ли иерархический список атомом

union // определение списка (атом или пара «голова-хвост»)

{ type_of_data atm;

struct head_tail

{ list *list_h, *list_t;

} pair;

};

~list();//деструктор (освобождает память)

};

list::~list()

{ if (!atomic)

{ delete pair.list_h;

delete pair.list_t;

}

}

// базовые функции для иерархических списков

bool isnull(list *l); // возвращает true, если список пустой

bool isatom(list *l); // возвращает true, если список атомарный

list *head(list *l); // возвращает указатель на голову

list *tail(list *l); // возвращает указатель на хвост

list *makeatom(type_of_data x); // возвращает атомарный список

type_of_data getatom(list *l); // возврашает значение атома

list *cons(list *l_head, list *l_tail); //формирует новый список

list *concat(list *l1, list *l2); // присоединение l2 к l1

void print(list *l); // вывод элементов списка l

main()

{ // для примера создаем список ( 1 ( 2 3 ) 4 5 ):

list *l=cons(makeatom(1), // голова

cons(cons(makeatom(2),cons(makeatom(3),NULL)),//хвост

cons(makeatom(4),cons(makeatom(5),NULL))));

print(l); cout<<endl;

// соединяем исходный список со списком ( ( 6 7 ) ):

l=concat(l,cons(cons(makeatom(6),cons(makeatom(7),NULL)),NULL));

// образуется список ( 1 ( 2 3 ) 4 5 ( 6 7 ) )

print(l); cout<<endl; return 0;

}

bool isnull(list *l)

{ return (l==NULL);

}

bool isatom(list *l)

{ if (isnull(l)) return false;

return l->atomic;

}

list *head(list *l)

{ if (isnull(l)) { cerr<<"!head(NULL)"; exit(1); }

if (isatom(l)) { cerr<<"!head(atom)"; exit(2); }

return l->pair.list_h;

}

list *tail(list *l)

{ if (isnull(l)) { cerr<<"!tail(NULL)"; exit(3); }

if (isatom(l)) { cerr<<"!tail(atom)"; exit(4); }

return l->pair.list_t;

}

list *makeatom(type_of_data x)

{ list *temp=new list;

temp->atomic=true; temp->atm=x;

return temp;

}

type_of_data getatom(list *l)

{ if (!isatom(l)) { cerr<<"getatom(!atom)"; exit(5); }

return l->atm;

}

list *cons(list *l_head, list *l_tail)

{ if (isatom(l_tail)) { cerr<<"!cons(l_head,atom)";exit(6);}

list *temp=new list; temp->atomic=false;

temp->pair.list_h=l_head; temp->pair.list_t=l_tail;

return temp;

}

list *concat(list *l1, list *l2)

{ if (isnull(l1)) return l2;

if (isatom(l1)) return cons(l1,l2);

return cons(head(l1),concat(tail(l1),l2));

}

void print(list *l)

{ if (isnull(l)) return;

if (isatom(l)) cout<<getatom(l)<<" ";

else

{ if (isatom(head(l))) print(head(l));

else

{ cout<<"( "; print(head(l)); cout<<") ";

}

print(tail(l));

}

}