栈和队列



1.栈

(1)后进先出;
         实现:栈顶指针指向栈顶元素,插入时先修改指针再插入,删除时先取栈顶元素再修改指针;
         栈顶元素S[S.top],栈底元素S[1];
         只能在栈顶上插入和删除;
(2)栈数据结构(用vector实现也行,更简单):
         int top;    //栈顶指针
         int stackLen;//栈长度
         int *data;//指向栈数组
(3)在栈上实现的操作:
         STACK-EMPTY(S)//判断栈是否为空
         PUSH(S, x)            //把x压入到栈顶
         POP(S)                 //取出并返回栈顶元素
 下面是实现代码:
/*
栈的实现:数组为基础数据结构
*/
class Stack{
private:
	int top;//栈顶指针
	int dataLen;//栈数组大小
	int *data;
	Stack(){}
public:
	Stack(int stackSize){
		dataLen = stackSize;
		top = -1;
		data = new int[stackSize];
	}
	~Stack(){delete []data;}
	bool IsEmpty();
	int Pop();
	void Push(int x);
	void printStack();
};
bool Stack::IsEmpty()
{
	return top<0 ;
}
void Stack::Push(int x)
{
	if(top>=dataLen-1){
		cerr<<"栈上溢!"<<endl;
		return;
	}
	data[top+1] = x;
	top++;
}
int Stack::Pop()
{
	if(top<0){
		cerr<<"栈下溢!"<<endl;
		return INT_MIN;
	}
	int val = data[top];
	top--;
	return val;
}
void Stack::printStack()
{
	//---栈底到栈顶顺序输出
	for(int i=0 ; i<dataLen ; i++)
		cout<<data[i]<<" ";
	cout<<endl;
}

补充说明:

       1.最先进栈的元素是不是就只能是最后出栈呢?
       答:不一定,栈只是对入栈出栈的位置作了限制,并没有对元素的进出时间进行限制。如1、2、3依次进栈,可能的出栈顺序有:
             1进1出2进2出3进3出---123序;1进1出2进3进3出2出---132序;1进2进2出1出3进3出---213序;1进2进3进3出2出1出---321序;1进2进2出3进3出1出---231序。最先进栈的元素1可以最先出栈,出栈顺序与时间无关的。

       2.双向栈:两栈共享存储空间(数组),前提是对于两个栈中数据类型相同,可以让栈A栈顶从0开始,栈B栈顶从M-1开始。于是二者的判空条件分别为topA==-1与topB==M;判满条件是topA+1==topB。代码很简单,不需要作过多讲解。Push与Pop的时候用一个标志位进行标记是对哪个栈进行操作即可。

/*
双向栈的实现
*/
typedef int ElemType;
#define MAXSIZE 100
struct SqDoubleStack
{
	SqDoubleStack():topA(-1),topB(MAXSIZE){}
	ElemType data[MAXSIZE];
	int topA;
	int topB;
	bool Push(ElemType e , int stackNumber);
	bool Pop(ElemType *e , int stackNumber);
	void printStack(int stackNumber);

};
bool SqDoubleStack::Push(ElemType e , int stackNumber)
{
	if(topA+1 == topB)       //栈已满,不能再push新元素了
		return false;
	if(stackNumber == 1)           //栈A有元素进栈
		data[++topA] = e;    //若栈1则先top+1后给数组元素赋值
	else if(stackNumber == 2)      //栈B有元素进栈
		data[--topB] = e;    //若栈2则先top2-1后给数组元素赋值
	return true;

}
//若栈不空,则删除s的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
bool SqDoubleStack::Pop(ElemType *e , int stackNumber)
{
	if(stackNumber == 1)
	{
		if(topA == 1)
			return false;            //说明栈1已经是空栈,溢出
		*e = data[topA--];     //将栈1的栈顶元素出栈 
	}
	else if(stackNumber == 2)
	{
		if(topB == MAXSIZE)
			return false;            //说明栈2已经是空栈,溢出
		*e = data[topB++];     //将栈2的栈顶元素出栈
	}
	return true;
}
//---由栈底到栈顶打印元素
void SqDoubleStack::printStack(int stackNumber)
{
	if(stackNumber == 1)
	{
		if(topA == 1)//栈A是空栈
			return;
		for(int i=0 ; i<=topA ; i++)
			cout<<data[i]<<" ";
		cout<<endl;
	}
	else if(stackNumber == 2)
	{
		if(topB == MAXSIZE)//栈B是空栈
			return ;            
		for(int i=MAXSIZE-1 ; i>=topB ; i--)
			cout<<data[i]<<" ";
		cout<<endl;
	}
}
int main()
{
	SqDoubleStack stack;
	for(int i=0 ; i<9 ; i++)
		stack.Push(i+1,1);
	for(int i=0 ; i<9 ; i++)
		stack.Push(i+1,2);
	stack.printStack(1);
	stack.printStack(2);
	return 0;
}
       3.栈的链式存储结构:
        由于链栈的栈顶可以作为链表的头结点,因此链栈不需要头结点。链栈基本不存在栈满的情况,除非内存已经没有可用的空间,如果真是如此操作系统已近面临死机崩溃的问题,而不是链栈是否溢出的问题。链栈判空条件就是top==NULL,链栈绝大部分操作都与单链表类似,只在插入和删除上特殊一些。

/*
链栈的实现
*/
typedef int ElementType;
struct StackNode{
	StackNode():next(NULL){}
	ElementType data;
	StackNode *next;
};
class LinkStack{
private:
	StackNode* top;//栈顶指针
	int count;//链栈内元素个数
	void destory();//释放链栈申请内存
public:
	LinkStack():top(NULL){}
	~LinkStack();
	bool Push(ElementType e);
	bool Pop(ElementType *e);
	bool StackEmpty();
	void printLinkStack();
};
LinkStack::~LinkStack()
{
	destory();
	top = NULL;
}
bool LinkStack::StackEmpty()
{
	return (NULL == top);
}
void LinkStack::destory()
{
	StackNode *p = top;
	StackNode *t;
	while(p){
		t = p;
		p = p->next;
		delete t;
		t = NULL;
	}
}
bool LinkStack::Push(ElementType e)
{
	//---无需判满
	StackNode* t = new StackNode;
	t->data = e;
	t->next = top;
	top = t;
	count++;
	return true;
}
bool LinkStack::Pop(ElementType *e)
{
	if(StackEmpty())//空栈
		return false;
	*e = top->data;
	StackNode *t = top;
	top = top->next;
	delete t;
	count--;
	return true;
}
//---从顶到底打印元素
void LinkStack::printLinkStack()
{
	if(StackEmpty())//空栈
		return;
	StackNode *p = top;
	while(p){
		cout<<p->data<<" ";
		p = p->next;
	}
	cout<<endl;
}
int main()
{
	LinkStack stack;
	for(int i=0 ; i<9 ; i++)
		stack.Push(i+1);
	stack.printLinkStack();
	return 0;
}

2.队列

 (1)先进先出;
          实现:队列的头指针指向队列首元素,删除时先取队列首元素再修改指针,队列的尾指针指向队尾元素的下一个元素,插入时先插入再修改指针;
          队头元素Q[head],队尾Q[tail];
          只能在队头出队,队尾入队。
(2)数组队列的结构:
          int tail;      //队尾,指向最新进入的元素
          int head;  //队头,指向最先出的元素
          int length;//队列的长度
          int *data; //指向队列数组
(3)在队列上实现的操作:
          ENQUEUE(Q, x)            //把x插入到队列尾
          DEQUEUE(Q)                //取出队列首元素并返回
    说明:1.对于数组实现的队列,可能会出现“假溢出”的情况,于是常常实现为循环队列,对于循环队列有两种判定是否为空可以用flag==0&&front==rear,为满可以用flag==1&&front==rear;还可以预留一个空位,如果为空rear==front,为满(rear+1)%QueueSize==front。
               2.对于队列自然也有链队列,此时对头指针指向链队列的头结点队尾指针指向终端节点。
/*
链队列的实现
*/
//链式队列的结点类型定义
typedef int ElemType;
struct QNode{
	QNode():next(NULL){}
	ElemType data;                 
	QNode *next;                 
};
//链式队列
class LinkQueue{
private:
	QNode*  front;                
	QNode*  rear;
public:
	LinkQueue():front(NULL),rear(NULL){
		QNode *t = new QNode;
		front = rear = t;
		front->next = rear->next = NULL;
	}

	~LinkQueue(){
		while(front)
		{
			rear = front->next;
			delete(front);
			front = rear;
		}
	}
	int QueueLength();
	void EnQueue(ElemType e);
	bool DeQueue(ElemType &e);
};

//求队列的长度
int LinkQueue::QueueLength()
{
	QNode *p = front;    //p指向头结点
	int count = 0;
	while (p->next != NULL)
	{
		count++;
		p = p->next;
	}
	return count;
}

//队尾入队
void LinkQueue::EnQueue(ElemType e)
{ 

	QNode *p = new QNode;
	if(!p)
		exit(OVERFLOW);
	p->data = e;
	p->next=NULL;  //生成一个数据为X的结点
	rear ->next = p ;    //将结点P插入队尾
	rear = p;          //修改队尾指针,令其指向P结点
}

//队首(头结点的后继)出队
bool LinkQueue::DeQueue(ElemType &e) 
{
	//链队列Q为空
	if(front->next = NULL) 
		return false;
	QNode* p = front->next; //令p指向队列Q的第一个有效节点 
	e = p->data;             
	front->next =  p->next;//修改队头指针
	if(rear == p) //被删除的是队尾结点,修改rear为front
		rear = front;  
	delete p;
	return true;
}
下面是普通队列的实现代码:
/*
队列的实现:数组为基础数据结构
*/
class Queue
{
public:
	Queue(){}
	Queue(int QSize):dataLen(QSize),front(0),rear(0){
		data = new int[QSize];
	}
	~Queue(){delete []data;}

	void printQueue();
	void EnQueue(int x);
	int DeQueue();
	bool isEmpty();
	bool isFull();
private:
	int *data;
	int dataLen;//有效数据为dataLen-1,留空作为判空和判满标识
	int front;//对头指针,指向第一个有效元素位置
	int rear;//队尾指针,最后一个有效元素的下一个位置
};
bool Queue::isEmpty()
{
	return front==rear;
}
bool Queue::isFull()
{
	return (rear+1)%dataLen==front;
}
//从头到尾输出元素
void Queue::printQueue()
{
	if (isEmpty()){
		cout<<"队列已空!"<<endl;
		return;
	}
	if(front<rear){//对头在队尾前面
		for(int i=front ; i<rear ; i++)
			cout<<data[i]<<" ";
		cout<<endl;
	}else{//对尾在队头前面
		for(int i=front ; i<=dataLen-1 ; i++)
			cout<<data[i]<<" ";
		for(int i=0 ; i<rear ; i++)
			cout<<data[i]<<" ";
		cout<<endl;
	}
}
void Queue::EnQueue(int x)
{
	if(isFull()){
		cout<<"队列已满!"<<endl;
		return;
	}
	data[rear] = x;
	if(rear == dataLen-1)//队尾指向最后位置
		rear = 0;//循环数组
	else
		rear++;
}
int Queue::DeQueue()
{
	if(isEmpty()){
		cout<<"队列已空!"<<endl;
		return INT_MIN;
	}
	int val = data[front];
	if(front == dataLen-1)//对头指向最后位置
		front = 0;
	else
		front++;
	return val;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值