栈
栈的定义:栈是限定仅在表尾进行插入和删除的线性表。从栈的定义,我们可以知道栈是线性表的一种特殊情况,与线性表不同,栈中元素的弹出(pop)和压入(push)都只能在栈顶进行,对于我们编程来讲,我们不必考虑是否需要在某个地方插入,某个地方删除。也不必考虑在特殊节点做特别的处理。同线性表相同,栈也可以用数组或者用链表来描述。在栈中,很重要的一个东西就是栈顶,通常我们会用Top来指示栈顶所在的位置,我们可以形象地把栈必成是一叠盘子(如图1),因为盘子是一块块叠上去的,并且要拿到最后一块盘子,你必须先拿起最后一块盘子上面的盘子,这跟栈的特性先进后出一样。其中Top就是用来指向盘子顶(栈顶)的。
图1 一叠盘子
下面我们就分别实现这数组和链表两种方式来实现栈。
在具体地实现栈之前,我们先来实现栈的抽象接口
interface IStack<T>
{
int GetLength(); //求栈的长度
bool IsEmpty(); //判断栈是否为空
void Clear(); //清空操作
void Push(T item,out States mtates); //入栈操作
T Pop(out States mtates); //出栈操作
T GetTop(out States mtates); //取栈顶元素
}
其中,States是一个枚举量,只有Success和Fail两种状态。
-
1、栈的顺序存储结构及实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataStructure.Stack
{
class SeqStack<T>: IStack<T>
{
privateconstint maxsize =100; // 顺序栈的容量
private T[] data =new T[maxsize];//数组,用于存储顺序栈中的数据元素
privateint top =-1; // 指示顺序栈的栈顶
public SeqStack()
{
}
public SeqStack(T[] data)
{
Array.Copy(data,this.data, data.Length);
top = data.Length -1;
}
publicbool IsFull
{
get
{
return top +1== maxsize ?true:false;
}
}
publicint GetLength()
{
return top +1;
}
publicbool IsEmpty()
{
return top ==-1?true:false;
}
publicvoid Clear()
{
top =-1;
}
publicvoid Push(T item,out States states)
{
if(IsFull ==true)
{
states = States.Fail;
}
else
{
states = States.Success;
data[++top]= item;
}
}
public T Pop(out States states)
{
if(IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
else
{
states = States.Success;
return data[top--];
}
}
public T GetTop(out States states)
{
if(IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
else
{
states = States.Success;
return data[top];
}
}
}
}
-
2、两栈共享空间
-
对于两栈共享空间,我们的构想是当Stack1空间不够的时候,就挪用Stack2的空间。为了不影响Stack2的正常使用,当Stack1空间不够时,我们将从Stack2的尾部开始挪用他的空间。两栈共享空间将大大提高空间的利用率。(两栈共享空间的示意图如下)
-
在这里,我们需要对原先的栈的顺序存储结构进行一些改造,主要的改造是:
-
1、将栈的存储容量由原来的在代码中直接指定,改成由构造函数指定;
-
2、创建一个新的方法 public void UseExtraSpace(SeqStack<T> Stack2),用来注入另一个栈的引用。注意,这里两个栈的类型必须是相同的;
-
3、增加一个用来保存另一个栈引用的字段otherStack;
-
4、增加一个字段来保存第二个栈的Top。
-
5、为了方便对Stack2中的数据域进行操作,我们将Stack中的数据域的可访问性变成Public。
在以下的代码中,我们认为Stack1和Stack2要么数据域没有值,要么至少有一个值。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataStructure.Stack
{
class SeqStack<T>: IStack<T>
{
privateint top1 =-1; // 指示顺序栈的栈顶
privateint top2 =-1;
privateint maxsize;
publicint MaxSize
{
get {return maxsize;}
private set { maxsize = value;}
}
public T[] data; //数组,用于存储顺序栈中的数据元素
SeqStack<T> otherStack;
public SeqStack()
{
}
/// <summary>
/// SeqStack构造函数
/// </summary>
/// <param name="MaxSize"> 顺序栈的容量 </param>
public SeqStack(int MaxSize)
{
data =new T[MaxSize];
this.maxsize = MaxSize;
}
public SeqStack(T[] data)
{
data =new T[4];//数组,用于存储顺序栈中的数据元素
Array.Copy(data,this.data, data.Length);
top1 = data.Length -1;
this.maxsize =4;
}
privatevoid IsUseExtraSpace(){
if(otherStack!=null)
{
bool isUseTop2 = top2 ==(otherStack.MaxSize -1)?false:true;
}
else
{
}
}
/// <summary>
/// 使用两栈共享空间
/// </summary>
/// <param name="Stack2">栈2</param>
/// <returns>操作是否成功</returns>
publicbool UseExtraSpace(SeqStack<T> Stack2)
{
if(this.GetType()==Stack2.GetType())
{
this.otherStack = Stack2;
top2 = Stack2.MaxSize -1;
returntrue;
}
else
{
returnfalse;
}
}
publicbool IsThisStackFull
{
get
{
return lenth >= maxsize ?true:false;
}
}
privateint lenth=0;
publicint Lenth
{
get {return lenth;}
private set { lenth = value;}
}
publicint GetLength()
{
return Lenth;
}
publicbool IsEmpty()
{
return top1 ==-1?true:false;
}
publicvoid Clear()
{
top1 =-1;
}
publicvoid Push(T item,out States states)
{
if(IsThisStackFull ==true)
{
bool IsStack2Full =(top2-(otherStack.GetLength()-1)) ==1;//如果top2和Stack2的top相邻,就说明Stack2满了
if(otherStack !=null&&!IsStack2Full)
{
states= otherStack.InsertFromButtom(top2--, item);
this.lenth++;
}
else
{
states = States.Fail;
}
}
else
{
states = States.Success;
this.lenth++;
data[++top1]= item;
}
}
public States InsertFromButtom(int index,T item){
//判断栈2是否已经满了
if((index -(this.GetLength()-1))==0)//满了
{
return States.Fail;
}
else//未满
{
this.data[index]= item;
return States.Success;
}
}
public T Pop(out States states)
{
if(IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
else
{
states = States.Success;
T dataToReturn =this.GetLength()<=this.MaxSize ?this.data[top1--]:this.otherStack.data[++top2];
this.lenth--;;//top-1+1=top
return dataToReturn;
}
}
public T GetTop(out States states)
{
if(IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
else
{
states = States.Success;
T dataToReturn =this.GetLength()<=this.MaxSize ?this.data[top1]:this.otherStack.data[top2];
return dataToReturn;
}
}
}
}
总结:两栈共享空间的难度主要在于出栈和入栈时对Stack1或者Stack2的选择上,其中我们可以利用Stack1.getLenth来判断,当Stack1.getLenth大于Stack1.MaxSize时,选择用Stack2;反之,选择Stack1.
-
3、栈的链式存储结构及实现
-
栈的链式存储结构简称链栈。链栈和普通的单链表比较,他们的不同之处基本上也就是插入和删除都在栈定进行这点不同。在栈的顺序存储结构中,我们需要考虑在数组的开头或结尾作为栈顶,最后我们选择了在数组的结尾作为栈顶。在单链表中,我们是不是也使用链表的尾巴来作为栈顶呢?如果我们使用链表尾作为栈顶,那么我们需要保存一个头节点和一个尾节点。或者保存一个头节点,然后每次都遍历到链表尾(时间复杂度为O(n))。其实在单链表中,我们已经引入了头节点,当我们从头节点处开始弹出(Pop)或压入(Push)元素的时候,我们就可以重复利用头节点,将头节点作为栈顶(Top)。
-
链栈实现的代码
-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DataStructure.Stack
{
class LinkStack<T>: IStack<T>
{
class Node<T>
{
private T data;
/// <summary>
/// 数据域
/// </summary>
public T Data
{
get {return data;}
set { data = value;}
}
private Node<T> next;
/// <summary>
/// 引用域
/// </summary>
public Node<T> Next
{
get {return next;}
set { next = value;}
}
//头结点构造函数
public Node(Node<T> node)
:this(default(T), node)
{
}
//普通结点构造函数
public Node(T data, Node<T> node)
{
this.Data = data;
this.Next = node;
}
/// <summary>
/// 空构造函数
/// </summary>
public Node()
:this(default(T),null)
{
}
//尾结点构造函数
public Node(T data)
:this(data,null)
{
}
}
privateint lenth=0;
publicint Lenth
{
get {return lenth;}
set { lenth = value;}
}
private Node<T> top;
public LinkStack()
{
}
public LinkStack(T[] t)
{
States mStates;
for(int i =0; i < t.Length; i++)
{
this.Push(t[i],out mStates);
}
}
publicint GetLength()
{
returnthis.Lenth;
}
publicbool IsEmpty()
{
return top ==null?true:false;
}
publicvoid Clear()
{
this.top =null;
}
publicvoid Push(T item,out States states)
{
if(this.top==null)//头节点
{
this.top =new Node<T>(item);
}else //普通节点
{
Node<T> NodeToPush =new Node<T>(item,this.top);
this.top = NodeToPush;
}
states = States.Success;
this.lenth++;
}
public T Pop(out States states)
{
if(this.IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
Node<T> NodeToPop=this.top;
this.top = NodeToPop.Next;
this.Lenth--;
states = States.Success;
return NodeToPop.Data;
}
public T GetTop(out States states)
{
if(IsEmpty()==true)
{
states = States.Fail;
returndefault(T);
}
else
{
states = States.Success;
returnthis.top.Data;
}
}
}
}
作者:kissazi2
出处:http://www.cnblogs.com/kissazi2/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。