数据结构:广义表
关于广义的表定义见下文的链接,暂不赘述。
总结:二维及以上的数组可以看作是特殊的广义表。
这几篇文章都特别不错,先把链接贴在这里,之后再整理:
- 封装成C++类的代码:C++如何实现广义表详解 - C/C++开发社区 | CTOLib码库
- 图画的不错,把广义表画成类似树的结构,同时还有其他数据结构的总结👍:【数据结构】广义表 - Tim的资源站 (timsrc.com)
- 讲了如何用广义表存储多项式:数据结构(六):广义表 (emous.github.io)
- 这个GitHub仓库里面也有其他数据结构的总结:Jack-Lee-Hiter/AlgorithmsByPython/数据结构.md - github.com
其他几个链接:
- 广义表相关总结 - WhiteBlackCat - 博客园 (cnblogs.com)
- 广义表的一些概念 - 简书 (jianshu.com)
- c++数据结构之广义表 - 编程语言 - 亿速云 (yisu.com)
暂时没有见到用继承和多态实现广义表的代码,自己写了一个:
glist.hpp
#ifndef GLIST_HPP
#define GLIST_HPP
template<typename T>
class GListElement {
public:
enum GListElementType {ATOM, LIST};
GListElement(GListElementType _type) :
element_type(_type) {}
virtual ~GListElement() = default;
GListElementType type() { return element_type; }
bool equal_type(const GListElement<T> & a) { return this->type() == a.type(); }
virtual T& data() = 0;
protected:
GListElementType element_type;
};
template<typename T>
class GAtom : public GListElement<T>
{
private:
T element;
public:
GAtom() :
GListElement<T>(GListElement<T>::ATOM) {}
// GAtom(T && e) :
// GListElement<T>(GListElement<T>::ATOM), T(e) {}
GAtom(const T & e) :
GListElement<T>(GListElement<T>::ATOM), element(e) {}
~GAtom() {};
GAtom & operator=(const T & val) { element = val; return *this; }
T& data() { return element; };
};
template<typename T>
class GList : public GListElement<T>
{
struct node {
GListElement<T>* element_ptr;
node* next;
node* prior;
node() :
element_ptr(nullptr), next(this), prior(this) {};
node(GListElement<T>* _ptr, node * _n = nullptr, node * _p = nullptr) :
element_ptr(_ptr), next(_n), prior(_p) {};
~node() { delete element_ptr; }
};
node * head;
public:
GList() : GListElement<T>(GListElement<T>::LIST) { head = new node(); }
GList(const GList & glist) :
GListElement<T>(GListElement<T>::LIST) {
head = new node();
GListElement<T>* item_ptr = nullptr;
for (auto item : glist) {
switch (item->type())
{
case GListElement<T>::ATOM:
item_ptr = new GAtom<T>(*dynamic_cast<GAtom<T>*>(item)); break;
case GListElement<T>::LIST:
item_ptr = new GList<T>(*dynamic_cast<GList<T>*>(item)); break;
}
auto last = head->prior;
auto new_node = new node(item_ptr, head, last);
last->next = new_node;
head->prior = new_node;
}
}
~GList() {
auto node_ptr = head->next;
while (node_ptr != head) {
auto tmp = node_ptr; node_ptr = node_ptr->next; delete tmp;
}
delete head;
}
T& data() { return head->next->element_ptr->data(); }
friend class iterator;
class iterator {
node * the_node;
public:
iterator(const GList & glist) {
the_node = (glist.head)->next;
}
iterator(node * _node) : the_node(_node) {}
iterator & operator++() { // pre increment
the_node = the_node->next;
return *this;
}
iterator operator++(int) { // post increment
auto tmp = *this;
the_node = the_node->next;
return tmp;
}
bool operator==(const iterator & rhs) {
return the_node == rhs.the_node ||
(the_node->element_ptr == nullptr && rhs.the_node->element_ptr == nullptr);
}
bool operator!=(const iterator & rhs) { return the_node != rhs.the_node; }
GListElement<T>* operator*() { return (the_node->element_ptr); }
};
iterator end() const { return iterator(head); };
iterator begin() const { return iterator(*this); };
void push_back(const T & item) {
GListElement<T>* item_ptr = nullptr;
item_ptr = new GAtom<T>(item);
auto last = head->prior;
auto new_node = new node(item_ptr, head, last);
last->next = new_node;
head->prior = new_node;
}
void push_back(const GList<T> & item) {
GListElement<T>* item_ptr = nullptr;
item_ptr = new GList<T>(item);
auto last = head->prior;
auto new_node = new node(item_ptr, head, last);
last->next = new_node;
head->prior = new_node;
}
int depth() {
int depth = 0;
for (auto i : *this) {
if (i->type() == GListElement<T>::LIST) {
auto sublist_ptr = dynamic_cast<GList<T>*>(i);
auto t = sublist_ptr->depth();
if (t > depth) depth = t;
}
}
return depth + 1;
}
};
#endif
对移动语义还不完全了解,暂时无法优化。
迭代器解引用之后得到的是基类GListElement<T>
的指针,如此,迭代器的operator->
就不是很有意义了,便不实现了。
关于如何使用看下边的代码:
glist_test.cpp
#include "glist.hpp"
#include <iostream>
template<typename T>
void print_glist(const GList<T> & list, int depth = 0) {
std::cout << "(";
for (auto i : list) {
if (i->type() == GListElement<T>::LIST) {
auto sublist_ptr = dynamic_cast<GList<T>*>(i);
print_glist<T>(*sublist_ptr, depth+1);
}
else { std::cout << i->data(); }
std::cout << ",";
}
std::cout << "\b)";
}
int main() {
GList<char> list;
list.push_back('a');
list.push_back('b');
list.push_back(list);
list.push_back('c');
for (auto i : list) {
std::cout << i->data() << ' ';
}
print_glist(list);
std::cout << " depth: " << list.depth() << std::endl;
}