考试前复习下数据结构,把一些知识点整理在这!主要参考了殷人昆主编的《数据结构(用面向对象方法与C++语言描述)》这本书,以及中山大学刘聪老师的课件内容!
概念与性质
线性表(Linear List)是由n(n≥0)个数据元素(结点)a[0],a[1],a[2]…,a[n-1]组成的有限序列。——[维基百科]
线性表是一个有限序列,意味着表中各个表项是相继排列的,且每两个相邻表项之间都有直接前驱和直接后继的关系。除第一个表项外,其他表项有且仅有一个直接前驱;除最后一个表项外,其他表项有且仅有一个直接后继。
类的定义
以下LinearList类给出了线性表的抽象基类,它应用了模板类来描述线性表抽象数据类型:
template <class T>
class LinearList {
public:
LinearList(); // 构造函数
~LinearList(); // 析构函数
virtual int Size() const = 0; // 求表最大体积
virtual int Length() const = 0; // 求表长度
virtual int Search(T & x) const = 0; // 在表中搜索给定值x
virtual int Locate(int i) const = 0; // 在表中定位第i个元素位置
virtual bool getData(int i, T & x) const = 0; // 取第i个表项的值
virtual void setData(int i, T & x) = 0; // 修改第i个表项的值为x
virtual bool Insert(int i, T & x) = 0; // 在第i个表项后插入x
virtual bool Remove(int i, T & x) = 0; // 删除第i个表项,通过x返回
virtual bool isEmpty() const = 0; // 判表空
virtual bool isFull() const = 0; // 判表满
virtual void Sort() = 0; // 排序
virtual void Input() = 0; // 输入
virtual void Output() = 0; // 输出
virtual LinearList<T> operator=(LinearList<T> & L) = 0; // 复制
};
存储方式
线性表的存储表示有两种:顺序存储方式(基于数组)和链表存储方式(基于链表)。
顺序表
定义
把线性表中的所有表项按照其逻辑顺序依次存储到计算机存储中指定存储位置开始的一块连续的存储空间中。
特点
用物理位置上的邻接关系来表示结点间的逻辑关系。
优点
- 无需为表示结点间的逻辑关系而增加额外的存储空间,存储利用率高。
- 支持随机存取,存取速度快。
缺点
- 插入删除时,平均需要移动一半的元素,效率低。
- 若是静态分配存储空间,则很难事先确定合适的空间大小;若是动态分配内存空间,则在扩充数组空间时,时间开销较大。
链表
单链表
定义
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
单链表c++实现
template <typename T>
class LinkedList {
public:
LinkedList() {
first = NULL;
}
~LinkedList() {
while (first != NULL) {
removeFirst();
}
}
LinkedList(LinkedList & that) {
copy(that);
}
LinkedList & operator= (LinkedList & that) {
while (first != NULL) {
removeFirst();
}
copy(that);
return *this;
}
void removeFirst() {
if (isEmpty())
return;
Node * node = first;
first = first->next;
delete node;
}
void addFirst(T data) {
Node * node = new Node();
node->data = data;
node->next = first;
first = node;
}
T getFirst() {
if (isEmpty()) {
throw runtime_error("The first element does not exist.");
}
return first->data;
}
bool isEmpty() {
return first == NULL;
}
private:
struct Node {
T data;
Node * next;
};
Node * first;
void copy(LinkedList & that) {
Node * current = NULL;
Node * node = that.first;
while (node != NULL) {
if (current == NULL) {
current = first = new Node();
} else {
current->next = new Node();
current = current->next;
}
current->data = node->data;
current->next = NULL;
node = node->next;
}
}
};
特点
通过单链表的指针将各个数据元素按照线性表的逻辑顺序链接起来。
优点
- 插入删除结点效率高
缺点
- 每个结点带有指针域,存储开销大。
- 不支持随机存取,遍历链表时间开销大。
为了解决单链表的缺点,出现了单链表的其他变形,如单向循环链表(循环链表)和双向循环链表(双链表)。
双链表
使用双向链表的目的是为了解决在链表中访问直接前驱和直接后继的问题。
双链表c++实现
template <typename E>
class list {
private:
struct Node {
E data;
Node * prev;
Node * next;
};
int nodeCount;
Node * first;
Node * last;
void clear() {
while (nodeCount > 0) {
pop_front();
}
}
void copy(list & that) {
Node * iterator = that.first;
for (int i = 0; i < that.nodeCount; ++ i) {
push_back(iterator->data);
iterator = iterator->next;
}
}
public:
list() {
nodeCount = 0;
}
~list() {
clear();
}
list(list & that) {
nodeCount = 0;
copy(that);
}
list & operator= (list & that) {
clear();
copy(that);
return *this;
}
int size() {
return nodeCount;
}
bool empty() {
return nodeCount == 0;
}
E front() {
if (nodeCount == 0)
throw runtime_error("The first element does not exist.");
return first->data;
}
E back() {
if (nodeCount == 0)
throw runtime_error("The last element does not exist.");
return last->data;
}
void push_front(E e) {
Node * node = new Node();
node->data = e;
if (nodeCount == 0) {
node->prev = node->next = node;
first = last = node;
}
else {
node->prev = last;
node->next = first;
first->prev = node;
last->next = node;
first = node;
}
++ nodeCount;
}
void push_back(E e) {
push_front(e);
last = first;
first = first->next;
}
void pop_front() {
if (nodeCount == 0)
throw runtime_error("The first element does not exist.");
-- nodeCount;
if (nodeCount == 0) {
delete first;
}
else {
first->next->prev = last;
last->next = first->next;
delete first;
first = last->next;
}
}
void pop_back() {
if (nodeCount == 0)
throw runtime_error("The last element does not exist.");
first = last;
last = last->prev;
pop_front();
}
};