数据结构与算法之----栈与队列

1、栈

1.1 栈的顺序存储结构


#include "stdafx.h"
#include<iostream>
#include<string.h>
using namespace std;

struct Sqstack
{
	int *data;
	int top;
	int maxsize;
	Sqstack():top(-1){} //初始化为-1
};
void Push(Sqstack &S,int e)
{
	if(S.top == S.maxsize-1)//把==写成了=,切忌以后不要再犯这样的错误
	{
		cout<<"out of range push"<<endl;
		return;
	}
	S.data[++S.top]=e;
}

void Pop(Sqstack &S)
{
	if(S.top==-1)
	{
		cout<<"out of range pop"<<endl;
		return;
	}
	S.top--;
}
int _tmain(int argc, _TCHAR* argv[])
{
	Sqstack S;
	cout<<"请输入栈的最大存储个数"<<endl;
	cin>>S.maxsize;
	S.data=new int[S.maxsize]();
	Push(S,1);
	cout<<S.data[S.top]<<endl;
	Pop(S);
	cout<<S.top<<endl;
	delete S.data;
	
	return 0;

}

输出:

请输入栈的最大存储个数
10
1
-1
Press any key to continue

思想:

(1)对于这种顺序存储结构的,要想动态化其大小,我的做法是在成员中添加maxsize,然后动态化其大小,初始化top为-1

(2)对于push操作,注意不要满,注意==不要粗心写成=,否则会让你蛋疼

(3)对于pop操作,注意不要空,注意top--


1.2 栈的链式存储结构

#include "stdafx.h"
#include<iostream>
#include<string.h>
using namespace std;

struct Node
{
	int data;
	Node *next;
	Node():next(NULL){}
};
struct LinkStack
{
	Node* top;//指向栈顶
	int count;
	
};
void Push(LinkStack* &S,int e)
{
	Node *p=new Node();
	p->data=e;
	p->next=S->top; //这里要尤其注意,因为S->就是个指针,始终指向当前,而不用p->next=S->top->next
	S->top=p;
	S->count++;
}
void Pop(LinkStack *S)
{
	Node *p=S->top;
	S->top=p->next;
	delete p;
}
void PrintStack(LinkStack *S)
{
	Node *p=S->top;
	while(p)//从本身开始,这个和链表的插入地方不一样,不是p->next
	{
		cout<<p->data;
		p=p->next;
	}
}
void Delete(Node *p)
{
	if(p->next)Delete(p->next);
	cout<<p->data;
	delete p;
}
void DeleteStack(LinkStack *S)
{
	Delete(S->top);

}

int _tmain(int argc, _TCHAR* argv[])
{
	LinkStack *S=new LinkStack();
	for(int i=0;i<5;i++)
	{
		int a;
		cin>>a;
		Push(S,a);
	}
	PrintStack(S);
	cout<<'\n';
	Pop(S);
	PrintStack(S);
	cout<<'\n';
	DeleteStack(S);
	return 0;

}

输出:
0 1 2 3 4
43210
3210
0123请按任意键继续. . .
 
思想:
(1)存储结构:由两部分组成,top 和count 其中top为指向第一个节点的指针。
(2)这个是和链表最不一样的地方,这样就不要用next,因为指向的就是第一个。所以队列也需要头节点。
(3)链表之所以要留一个头节点,是方便插入操作,特别是要往头插的时候。
(4)入栈操作:新建节点, 其next为原来的第一个节点,然后新节点作为top,这样就是利用头插法,而且是在最头端,和链表不一样,不是在头节点后面的
(5)出栈操作:很简单
(6)删除栈:利用一个函数来封装,其删除方式和链表类似
(7)遍历:while(p),即可 也就是说从第一个节点开始。和链表也有点不一样
 

1.3 两栈共享空间

当两栈类型相同,而且当一个栈减少,另外一个栈增加时,可以用两栈共享空间。
(1)两个栈分别指向栈的两端,当入栈时,需要有一个标号,告诉函数是入哪个栈。并判断是否溢出
(2)出栈时也是一样,判断是否溢出即可。

1.4 栈的应用之 逆波兰表示法

数字表达式转化成逆波兰表达式:

遇到数字直接输出,遇到符号入栈,遇到右括号时出栈,遇到符号时,比较和栈顶元素,若优先级比栈顶元素低或者相同,则栈内元素依次出栈,同时将该符号入栈。

如(+比*低,比-相同,所以*-出栈,+入栈)。

9+(3-1)*3+10/2    为 931-3*+10 2/+

逆波兰表达式的运算:

遇到数字入栈,遇到符号,将栈顶元素进行运算,将结果入栈,依次类推

 


2、队列

2.1 队列的顺序存储结构

#include "stdafx.h"
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;

struct Squeue
{
	int *data;
	int maxsize;
	int front;
	int rear;
	Squeue():front(0),rear(0){}
};
void EnQueue(Squeue &Q,int e)
{
	if((Q.rear+1)%Q.maxsize==Q.front)//队列已满,实际定义为当还有一个元素的时候定义队列满
	{
		cout<<"out of range"<<endl;
		return;
	}	
	Q.data[Q.rear]=e;
	Q.rear=(Q.rear++)%Q.maxsize;
}
void DeQueue(Squeue &Q,int &e)
{
	if(Q.front==Q.rear)
	{
		cout<<"Queue is empty"<<endl;
		return;
	}
	e=Q.data[Q.front];
	Q.front=(Q.front++)%Q.maxsize;

}
int QueueLength(Squeue &Q)
{
	return (Q.rear-Q.front+Q.maxsize)%Q.maxsize;
}
int _tmain(int argc, _TCHAR* argv[])
{

	Squeue Q;
	cout<<"请输入队列长度"<<endl;
	cin>>Q.maxsize;
	Q.data=new int[Q.maxsize]();
	for(int i=0;i<3;i++)
	EnQueue(Q,i);
	cout<<QueueLength(Q)<<'\n';
	int e;
	DeQueue(Q,e);
	cout<<e;
	return 0;

}

输出:

请输入队列长度
4
3
0请按任意键继续. . .

思想:

(1)队列在初始状态下为rear=0 front=0  也就是说队列空位 front = rear 

(2)这里标记当还有一个空的时候为队列满(否则无法区分是队列空还是队列满了)即(rear+1)%maxsize=front

(3)队列的长度为 (rear-front+maxsize)%maxsize

(4)rear或者front前移的时候为 (rear+1)%maxsize

 

2.2 队列的链式存储结构

#include "stdafx.h"
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;

struct Node
{
	int data;
	Node *next;
};
struct LinkQueue
{
	Node *front;
	Node *rear;
};
void EnQueue(LinkQueue &Q,int e)
{
	Node *p=new Node();//只能在队尾插入,让队列更长,rear始终指向队尾
	p->data=e;
	Q.rear->next=p;
	Q.rear=p;
}
void DeQueue(LinkQueue &Q,int &e)
{	
	if(!Q.front->next)
	{
		cout<<"queue is empty";
		return;
	}
	Node *p=Q.front->next;
	Q.front->next=p->next;
	if(p==Q.rear)//当只有一个元素的时候,让rear也指向头指针,不然最后一个元素删掉,rear就不知道指哪了
		Q.rear=Q.front;
	e=p->data;
	delete p;
}
int _tmain(int argc, _TCHAR* argv[])
{

	LinkQueue Q;
	Q.front=new Node();
	Q.rear=Q.front;//指向同一头节点
	EnQueue(Q,1);
	EnQueue(Q,2);
	int e;
	DeQueue(Q,e);
	cout<<e;
	DeQueue(Q,e);
	cout<<e;
	DeQueue(Q,e);
	cout<<e;

	return 0;

}


输出:

12queue is empty2请按任意键继续. . .

思想:

(1)队列结构为 front 和rear节点组成

(2)队列建立的时候要先建立头节点,并将front和rear指向头节点

(3)入队操作:只能在队尾操作,也就是用尾插法,只对rear进行修改,队伍不断从后面加长,rear始终在最后

(4)出队操作:删除头节点后面的元素,当只有一个元素的时候,要将rear 也指向头节点,也就是说主要对front进行操作。

 

你可能感兴趣的:(数据结构与算法之----栈与队列)