数据结构——栈(stack)
一、顺序栈
栈(stack)是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
栈的特性是先进后出的原则,先入栈的数据后出栈。
C语言实现:
1、顺序栈的存储结构以及一些常用方法
typedef struct stack
{
ElemType *data;
int size;
int top;
}Stack, *pStack;
void InitStack(pStack stack);
void DestoryStack(pStack stack);
int Push(pStack stack, ElemType val);
int Pop(pStack stack, ElemType *res);
2、栈的初始化
void InitStack(pStack stack)
{
assert(stack != NULL);
stack->data = (ElemType *)malloc(sizeof(ElemType)* SIZE);
assert(stack->data != NULL);
stack->size = SIZE;
stack->top = 0; // -1
}
3、栈的判空判满以及扩容
void Expand(pStack stack) //扩容函数
{
assert(stack != NULL);
ElemType *s = (ElemType*)malloc(sizeof(ElemType)* stack->size * 2);
assert(s != NULL);
for (int i = 0; i < stack->top; ++i)
{
s[i] = stack->data[i];
}
free(stack->data);
stack->data = s;
stack->size *= 2;
}
int IsFull(pStack stack) //判满
{
assert(stack != NULL);
if (stack->top == stack->size)
{
return TRUE;
}
return FALSE;
}
int IsEmpty(pStack stack) //判空
{
assert(stack != NULL);
if (stack->top == 0)
{
return TRUE;
}
return FALSE;
}
当栈的top与size相等时即为栈满,这是我们需要对其进行扩容,增大栈的大小。
当栈的top为0时栈为空,此时不可删除栈中的数据。
4、入栈函数(push)
int Push(pStack stack, ElemType val)
{
assert(stack != NULL);
if (IsFull(stack))
{
Expand(stack);
if (IsFull(stack))
{
return FALSE;
}
}
stack->data[stack->top++] = val;
return TRUE;
}
在向栈中插入数据时需要先进行判满,如果栈此时未满,则可以直接进行插入,否则,需要为其增加空间。
5、出栈函数(pop)
int Pop(pStack stack, ElemType *res)
{
assert(stack != NULL);
if (IsEmpty(stack))
{
return FALSE;
}
*res = stack->data[--stack->top];
return TRUE;
}
出栈时则需要对其进行判空,如果为空,则不允许进行出栈,若不为空,可直接出栈。
注意:这里我将top与pop函数写在了一起,方便运算,想实现top函数只需要访问数组的第top个值就行。
6、栈的销毁
void DestoryStack(pStack stack)
{
assert(stack != NULL);
free(stack->data);
stack->data = NULL;
stack->size = 0;
stack->top = 0;
}
C++实现:
基本的储存储结构及一些方法
typedef int ElemType;
class Stack
{
private:
ElemType *_data;
int _top;
int _size;
bool IsFull(); //判满
bool IsEmpty(); //判空
void Expand(); //扩容
public:
Stack();
Stack(const Stack &src); //拷贝构造函数
Stack& operator= (const Stack& src); //等号运算符的重载
~Stack();
void Push(ElemType val); //入栈
bool Pop(); //出栈
ElemType GetTop(); //取栈顶元素
void show(); //打印整个栈
};
bool Stack::IsFull()
{
assert(this != NULL);
if (_top == _size)
{
return true;
}
return false;
}
bool Stack::IsEmpty()
{
assert(this != NULL);
if (_top == 0)
{
return true;
}
return false;
}
void Stack::Expand()
{
assert(this != NULL);
ElemType *s = new ElemType[SIZE * 2];
assert(s != NULL);
for (int i = 0; i < _top; ++i)
{
s[i] = _data[i];
}
delete[]_data;
_data = s;
_size *= 2;
}
Stack::Stack()
{
assert(this != NULL);
_data = new ElemType[SIZE];
assert(_data != NULL);
_top = 0;
_size = SIZE;
}
Stack::Stack(const Stack &src)
{
_data = new ElemType[sizeof(src._data)];
for (int i = 0; i < src._top; i++)
{
_data[i] = src._data[i];
}
_top = src._top;
_size = src._size;
}
Stack& Stack::operator= (const Stack& src)
{
if (this == &src)
{
return *this;
}
if (_data != NULL)
{
delete[]_data;
}
_data = new ElemType[sizeof(src._data)];
for (int i = 0; i < src._top; ++i)
{
_data[i] = src._data[i];
}
_top = src._top;
_size = src._size;
return *this;
}
Stack::~Stack()
{
if (NULL != _data)
{
delete[]_data;
_data = NULL;
_top = 0;
_size = 0;
}
}
void Stack::Push(ElemType val)
{
assert(this != NULL);
if (IsFull())
{
Expand();
}
_data[_top++] = val;
}
bool Stack::Pop()
{
assert(this != NULL);
if (IsEmpty())
{
return 0;
}
_top--;
return 1;
}
ElemType Stack::GetTop()
{
assert(this != NULL);
if (IsEmpty())
{
return 0;
}
return _data[_top - 1];
}
void Stack::show()
{
assert(this != NULL);
for (int i = 0; i < _top; i++)
{
cout << _data[i] << " ";
}
cout << endl;
}
二、链式栈
链式栈是一种数据存储结构,可以通过单链表的方式来实现,使用链式栈的优点在于它能够克服用数组实现的顺序栈空间利用率不高的特点,但是需要为每个栈元素分配额外的指针空间用来存放指针域。
链式栈就是将栈的先进后出的特性与链表相结合起来,顺序栈是利用数组进行的,这样就有一个缺陷,它的大小是固定的,当出现栈满的时候就要进行对栈的扩容,而链式栈有了链表的不是固定内存的好处,这样就不必每次都进行判满来判断是否需要进行扩容。
链式栈就直接用C++进行编写
#include<iostream>
using namespace std;
template<typename T>
class Mstack
{
public:
class Node;
Mstack()
{
_head = NULL;
_top = NULL;
}
~Mstack()
{
if (_head == NULL)
{
return;
}
while (_top != _head)
{
pop();
}
delete _head;
_head = _top = NULL;
}
void push(T val)
{
Node *p = new Node;
p->_val = val;
p->_next = NULL;
if (_head == NULL && _top == NULL)
{
_head = p;
_top = p;
}
else
{
_top->_next = p;
_top = p;
}
}
int pop()
{
if (_head == NULL)
{
return -1;
}
Node *p = _head;
while (p->_next != _top)
{
p = p->_next;
}
delete _top;
_top = p;
_top->_next = NULL;
}
T top()
{
return _top->_val;
}
void show()
{
Node *p = _head;
while (p != NULL)
{
cout << p->_val << " ";
p = p->_next;
}
cout << endl;
}
private:
class space
{
public:
static space* getSpace()
{
if (NULL == _space)
{
m.lock();
if (NULL == _space)
{
_space = new space();
}
m.unlock();
}
return _space;
}
private:
space()
{
Node *tmp = new Node[LEN];
int i = 0;
for (; i < LEN - 1; i++)
{
tmp[i]._next = &tmp[i + 1];
}
tmp[i]._next = NULL;
_pool = &tmp[0];
}
static space* _space;
Node* _pool;
friend class Node;
};
class Node
{
private:
T _val;
Node *_next;
static space* _space;
public:
Node()
{
_next = NULL;
}
Node(T val)
{
_val = val;
_next = NULL;
}
void *operator new(size_t size)
{
cout << "void *operator new(size_t size)" << endl;
if (_space->_pool == NULL)
{
m.lock();
if (_space->_pool == NULL)
{
Node *tmp = new Node[LEN];
int i = 0;
for (; i < LEN - 1; i++)
{
tmp[i]._next = &tmp[i + 1];
}
tmp[i]._next = NULL;
_space->_pool = &tmp[0];
}
m.unlock();
}
Node* mem = _space->_pool;
_space->_pool = _space->_pool->_next;
return mem;
}
void operator delete(void *p)
{
Node *tmp = (Node*)p;
tmp->_next = _space->_pool;
_space->_pool = tmp;
}
friend class Mstack;
};
Node* _head;
Node* _top;
};
template<typename T>
typename Mstack<T>::space* Mstack<T>::Node::_space = Mstack<T>::space::getSpace();
template<typename T>
typename Mstack<T>::space* Mstack<T>::space::_space = NULL;
int main()
{
Mstack<int> s;
for (int i = 0; i < 10; i++)
{
s.push(i);
}
s.pop();
cout << s.top() << endl;
s.show();
return 0;
}