目录
栈
栈限定在表的一端进行插入和删除操作的线性表。
栈顶:插入和删除端
栈底:另一端
空栈:不含任何元素的栈
特性:后进先出,先进后出
栈的功能:初始化、销毁、入栈、出栈、取栈顶元素、判空。
顺序栈
一维数组实现,下标为0作栈底,同时设置top变量指示栈顶元素的位置。
栈空:top = -1
栈满:top = StackSize-1
入栈:top++;出栈:top--
const int StackSize = 10;
template<typename T>
class SeqStack
{
T data[StackSize];
int top;
public:
SeqStack()//初始化
{
top = -1;
}
~SeqStack() {}//销毁
void Push(T x)//进栈
{
if (top == StackSize - 1)throw"上溢";
data[++top] = x;
}
T Pop()//出栈
{
if (top == -1)throw"下溢";
T x;
x = data[top--];
return x;//直接return data[top--]也ok
}
T GetTop()//取栈顶元素
{
return data[top];
}
int Empty()//判空
{
return(top == -1 ? 1 : 0);
}
};
链栈
通常为单链表表示。
template<typename T>
struct Node
{
T data;
Node<T>* next;
};
template<typename T>
class LinkStack
{
Node<T>* top;//栈顶为链栈的头指针
public:
LinkStack();//初始化
~LinkStack();//释放存储空间
void Push(T x);//进栈
T Pop();//栈顶元素出栈
T GetTop();//取栈顶元素
int Empty();//判空
};
构造函数:top置空
析构函数:单链表释放直接代入
进栈://肥肠easy 自己画个图就能理解
template<typename T>
void LinkStack<T>::Push(T x)
{
Node<T>* s = new Node<T>;
s->data = x;
s->next = top;
top = s;
}
出栈:
template<typename T>
T LinkStack<T>::Pop()
{
T x;
if (top == nullptr)throw"下溢";
x = top->data;
Node<T>* p = top;
top = top->next;
delete p;
return x;
}
取栈顶:直接return top->data,但是元素不要出栈。
判空:看top是否为空
顺序栈和链栈的比较
顺序栈和链栈的基本操作的时间复杂度为O(1),空间性能是唯一可比的。
顺序栈:有存储元素个数限制和空间浪费问题。
链栈:除非内存没有可用空间时才会栈满,但每个元素都有指针域,从而产生了结构性开销。
元素变化个数较大时用链栈,反之用顺序栈。
队列
只允许在一端进行插入操作,在另一端进行删除操作的线性表
队尾:允许插入的一端
队头:允许删除的一端
特性:先进先出
队列的功能:初始化、销毁、入队、出队、读取队头元素、判空
顺序队列
设置位置变量rear:
假设顺序队列的把队列的所有元素存储在数组的前n个单元,入队操作相当于追加,则时间复杂度为O(1);但是出队需要把每个元素向前移一个位置,时间复杂度为O(n)。
设置位置变量rear&front:
front 指向队头元素的前一个位置,rear 指向队尾元素的位置。
出队:front ++;入队rear++
循环队列
假溢出:因为设置了front后元素不移动,整个队列向数组的高端移动,产生了“单项移动性”。当元素被插入到数组中下标最大的位置后数组空间就用尽了,但是数组低端仍有空闲空间。
循环队列:解决假溢出 头尾相连的循环结构,
设存储队列的数组长度为 QueueSize, rear = (rear+1)%QueueSize
队空:front = rear
队满:rear = (front+1)%QueueSize
const int QueueSize = 100;
template<typename T>
class CirQueue
{
int front, rear;
T data[QueueSize];
public:
CirQueue();//初始化
~CirQueue() {};
void EnQueue(T x);//进队
T DeQueue();//出队
T GetHead();//获取队头元素
int Empty();//判空
};
初始化
template<typename T>
CirQueue<T>::CirQueue()
{
front = rear = QueueSize - 1;//front和rear指向同一处,一般为数组的高端
}
入队
template<typename T>
void CirQueue<T>::EnQueue(T x)
{
if ((rear + 1) % QueueSize == front)throw"上溢";
rear = (rear + 1) % QueueSize;//队尾在循环的意义下+1
data[rear] = x;
}
出队
template<typename T>
T CirQueue<T>::DeQueue()
{
if (front == rear)throw"下溢";
front = (front + 1) % QueueSize;
return data[front];
}
判空:front =rear
取队头元素:data[(front+1)%QueueSize]
链队列
队头指针始终指向链队列的头结点,队尾指针指向终端节点
template<typename T>
struct Node
{
T data;
Node<T>* next;
};
template<typename T>
class LinkQueue
{
private:
Node<T>* front, * rear;
}
入队
1:rear->next =s;
2:rear = s;
template<typename T>
void LinkQueue<T>::EnQueue(T x)
{
Node<T>* s = new Node<T>;
s->data = x;
rear->next = s;
rear = s;
s->next = nullptr;
}
出队
1:p=front->next;
2:front->next =p->next;
template<typename T>
T LinkQueue<T>::DeQueue()
{
if (front == rear)throw"下溢";
T x;
Node<T>* p = new Node<T>;
p = front->next;
x = p->data;
front->next = p->next;
if (p->next == nullptr)rear = front;//出对前队列长度为1
delete p;
return x;
}
取队头: return front->next->data
判空: front==rear
循环队列与链队列的比较
两者基本操作的时间复杂度均为O(1),可比的还是空间能动性。
(参考之前顺序栈和链栈的比较原理)
使用的书籍:《数据结构——从概念操C++实现(第三版)》王红梅 王慧 王新颖 编著
ps:美女的头发要肝没啦555