简介
- 链表
“排列在一行”的数据项的集合——在链表中的任何一个数据项上都可以进行插入和删除操作 - 堆栈(区分数据结构中的堆栈与存储结构中的堆和栈)
是编译器和操作系统中重要的数据结构:元素的插入和删除只能在堆栈的一端——栈顶进行。 - 队列
插入操作在队尾进行,删除操作在队列头进行,FIFO。 - 二叉树
便于数据搜索和排序,去重,以及把表达式编译为机器语言。
如果可以,始终倾向于标准库的容器、迭代器和算法。
自引用类
一个自引用类包含一个指向与它同类的对象的指针成员
class Node
{
public:
explicit Node(int);
void setData(int) const;
int getData();
void setNextPtr(Node *);
Node* getNextPtr() const;
private:
int data;
Node* nextPtr;
}
自引用类对象链接在一起组成链表、队列、堆栈、树等。
链表
一个自引用类对象的线性集合,其中的对象称为节点(node),通过指针链链接。
节点在内存中通常不是连续存储,逻辑上可以看成是连续的.
单向链表
循环单向链表
双向链表
循环双向链表
//***********************单向链表节点模板类*****************************
#ifndef LISTCODE_H
#define LISTCODE_H
template <typename NODETYPE>
class List; //前置声明,告诉ListNode 有一个List类,即使它尚未定义,这样可以将它声明为友元声明
template <typename NODETYPE>
class ListNode
{
friend class List<NODETYPE>; //声明为友类,便于List对象操作该类成员,提高性能
public:
explicit ListNode(const NODETYPE& info):data(info),nextPtr(nullptr){}
NODETYPE getData() const{ // 获取数据
return data;
}
private:
NODETYPE data;
ListNode<NODETYPE> *nextPtr;
};
// 单链表示例
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include "ListNode.h"
template < typename NODETYPE >
class List
{
public:
List() : firstPtr(nullptr),lastPtr(nullptr)
{
}
~List()
{
if(!isempty())
{
std::cout << "Destroying nodes...\n";
ListNode<NODETYPE> *currentPtr = firstPtr;
ListNode<NODETYPE> *tempPtr = nullptr;
while(currentPtr !=nullptr)
{
template = currentPtr;
std::cout << tempPtr->data << '\n';
currentPtr = currentPtr->nextPtr;
delete tempPtr;
}
}
std::cout << "All nodes destroyed.\n\n";
}
void inserAtFront(const NODETYPE& info) // 前端插入
{
ListNode<NODETYPE> *newPtr = getNewNode(info);
if (isempty())
{
firstPtr = lastPtr = newPtr; //可以连续赋值
}
else
{
newPtr->nextPtr = firstPtr;
firstPtr = newPtr;
}
}
void insertAtBack(const NODETYPE& info) //后端插入
{
ListNode<NODETYPE> *newPtr = getNewNode(onfo);
if (isempty())
{
lastPtr = firstPtr = newPtr; //可以连续赋值
}
else
{
lastPtr->nextPtr = newPtr;
lastPtr = newPtr;
}
}
bool removeFromFront(NODETYPE&value) // 从前端删除,被删除Node的值传给value,返回bool值。
{
if(isempty())
{
std::cout << "List is already empty,cannot remove.\n" ;
return false;
}
else
{
ListNode<typename NODETYPE> *temp = firstPtr;
if(firstPtr == lastPtr)
firstPtr == lastPtr = nullptr;
else
firstPtr = firstPtr->nextPtr;
value = firstPtr->data;
delete temp;
return true;
}
}
bool removeFromBack(NODETYPE&value) // 从后端删除,被删除Node的值传给value,返回bool值。
{
if(isempty())
{
std::cout << "List is already empty,cannot remove.\n" ;
return false;
}
else
{
ListNode<typename NODETYPE> *temp = lastPtr;
if(firstPtr == lastPtr)
{
firstPtr == lastPtr = nullptr;
}
else
{
ListNode<typename NODETYPE> *p = firstPtr;
while(p->nextPtr != lastPtr)
{
p = p->nextPtr;
}
lastPtr = p;
}
value = temp->data;
delete temp;
return true;
}
}
bool isempty() const
{
return firstPtr == nullptr;
}
private:
ListNode<NODETYPE> * firstPtr;
ListNode<NODETYPE> *lastPtr;
ListNode<NODETYPE> * getNewNode(const NODETYPE&value)
{
return new ListNode<NODETYPE>(value); //创建一个动态内存区存储一个ListNode对象,返回对象地址
}
};
#endif
堆栈
堆栈数据结构允许在堆栈顶部增加和删除节点,是FIFO数据结构。
一种实现的方法是将它作为一种有限制链表。
主要成员函数 push 压栈,pop 出栈。
堆栈的作用
- 函数调用,储存调用者变量和返回地址
- 函数返回调用者或抛出一个异常时,每个局部对象的析构函数(如果有)被调用,该函数的自动变量的空间出栈,变量销毁
- 在编译器中用来计算表达式和生成机器指令
基于List继承实现类模板Stack
// *************基于List模板的Stack类模板实现
#ifndef STACK_H
#define STACK_H
#include "List.h"
template <typename STACKTYPE>
class Stack :private List<STACKTYPE> //private继承,使得所有List成员函数在Stack中都是私有,只调需要的基类成员函数,其余的对外隐藏
{
public:
void push(const STACKTYPE& data)
{
insertFromFront(data);
}
void pop()
{
removeFromFront(STACKTYPE& data);
}
bool isStackEmpty() const
{
return this->isempty(); // 模板的特化才能解析出成员函数标识符名称,依赖于参数,没有参数的成员函数必须显式使用this指针。
}
};
#endif
isStackEmpty() 需要显式使用this指针,这样编译器可正确区分 模板中定义的标识符。
从属名称是一个依赖于模板参数的标识符,如调用removeFromFront依赖于参数data,它有一个依赖于模板参数STACKTYPE的类型,模板实例化后才可以解析出它的名字。
相反,无参函数的标识符是非从属名称,如父类List中的isempty, 在定义模板的地方,这样的标识符就已经解析好了,如果模板没有实例化,那么非从属名称的函数的代码还不存在,这时编译器会产生编译错误,显式地加上this指针就会根据模板参数调用基类的成员函数。
使用List对象组合实现模板类Stack
在Stack模板类中创建一个List对象,通过该对象实现stack操作。