标签:
前言:我也是即学即写的,难免有错误。欢迎之处这篇博文的不足之处。
栈是数据结构的一种,他的原理就是后进先出(先进后出是一样的道理),如图(无图言屌)
看到没,你如果把栈当成一个开口向上的容器的话,你最先存储的a1要想取出来,必须把上面的元素都取出来,而你最后一个存储的a5元素却可以第一个取出来。这就是后进先出。
PS:我这里的top是指向栈顶元素的,这里用到的top初值是-1.有的书中(好像是严蔚敏的)的top的初始值是0.所以top指向栈顶元素的上一个存储单元。我个人觉得还是top初始值为-1比较好。关于这个知识点下面详讲。
查了好多资料,我暂时不知道怎么更好的解释,待补充。
终于到代码阶段了,栈分为顺序栈和链栈(是不是与顺序表,链表很相似?答案是相似度很高啊...)
首先来看看BCL中的栈的基本操作:BCL就是visual studio 里面封装的栈Stack。直接拿来用就好。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 Stack<int> stack = new Stack<int>(); //这是定义一个栈的对象stack 7 stack.Push(6); //Push就是入栈的操作,它是没有返回值的,含一个参数,就是你要存储进栈里面的数值。我的栈是int类型的所以我Push一个6 8 stack.Pop(); //Pop有返回值,返回栈顶的元素并且把栈顶元素删掉,top指向下一个元素 9 stack.Peek(); //Peek有返回值,返回栈顶元素。与Pop的区别在于Peek不删除栈顶元素。 10 stack.Count(); //有返回值,返回栈里面的元素个数 11 stack.Clear(); //清空栈 12 13 } 14 }
这几个是比较常见的,还有一些其他的就不多叙述了。看到这里你有可能会说既然visual studio已经封装好栈了我直接用不就得了,那我不是已经学会栈了吗,真简单。是的,你现在已经学会栈这个数据结构了,但是算法呢?Pop,Peek它们内部是怎么实现的你知道吗?如果在某个偶然的条件下,BCL类不能用了,怎么办?所以要学这个算法,至少你可以自己写一个栈,用自己的代码,让BCL凉快去吧。(了解内部的构成后,其实用BCL也没什么不对。人家visual studio封装好的不用白不用...)
首先新建一个接口:
1 interface IStack<T> //这里的T是泛型的意思,就是你定义成什么类型T就是什么类型,相当于T是类型的一个代表 2 { 3 int Count{get; } 4 bool IsEmpty(); 5 int GetLength(); 6 void Push(T item); 7 T Pop(); 8 T Peek(); 9 }
然后新建一个类作为顺序栈,这个类继承接口:
1 class MyStack <T>:IStack<T> 2 { 3 private T [] Data; 4 private int top; 5 6 public MyStack(int size) 7 { 8 Data = new T[size]; 9 top = -1; 10 } 11 public MyStack():this(10) 12 { 13 top = -1; 14 } 15 16 public int Count 17 { 18 get { return top + 1; } 19 } 20 21 public bool IsEmpty() 22 { 23 return Count == 0; 24 } 25 26 public int GetLength() 27 { 28 return Count; 29 } 30 31 public void Push(T item) 32 { 33 Data[top + 1] = item; 34 top++; 35 } 36 37 public T Pop() 38 { 39 T item = Data[top]; 40 top--; 41 return item; 42 } 43 44 public T Peek() 45 { 46 return Data[top]; 47 } 48 }
完成了。在控制台里面调用一下看看行不行
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 //顺序栈 7 IStack<int> stack = new MyStack<int>(); 8 9 stack.Push(3); 10 stack.Push(8); 11 Console.WriteLine(stack.Count); 12 Console.WriteLine(stack.Peek()); 13 Console.WriteLine(stack.Count); 14 Console.WriteLine(stack.Pop()); 15 Console.WriteLine(stack.Count); 16 Console.ReadLine(); 17 18 } 19 }
运行结果:
新建一个类作为链栈的节点:
1 class Node<T> 2 { 3 private T data; 4 public T Data 5 { 6 get { return data; } 7 set { data = value; } 8 } 9 10 private Node<T> next; 11 internal Node<T> Next 12 { 13 get { return next; } 14 set { next = value; } 15 } 16 17 public Node() 18 { 19 data = default(T); 20 next = null; 21 } 22 public Node(T data) 23 { 24 this.data = data; 25 next = null; 26 } 27 public Node(T data, Node<T> next) 28 { 29 this.data = data; 30 this.next = next; 31 } 32 public Node(Node<T> next) 33 { 34 this.next = next; 35 data = default(T); 36 } 37 38 39 }
新建一个类作为链栈功能的实现,还是继承那个接口:
1 class ListStack<T>:IStack<T> 2 { 3 private Node<T> top; 4 private int count; 5 6 public int Count 7 { 8 get { return count; } 9 } 10 11 public bool IsEmpty() 12 { 13 return count == 0; 14 } 15 16 public int GetLength() 17 { 18 return count; 19 } 20 21 public void Push(T item) 22 { 23 Node<T> newNode = new Node<T>(item); 24 newNode.Next = top; 25 top = newNode; 26 count++; 27 } 28 29 public T Pop() 30 { 31 T data = top.Data; 32 top=top.Next; 33 count--; 34 return data; 35 } 36 37 public T Peek() 38 { 39 return top.Data; 40 } 41 }
在控制台运行试试
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 6 //链栈 7 IStack<int> stack = new ListStack<int>(); 8 stack.Push(3); 9 stack.Push(8); 10 Console.WriteLine(stack.Count); 11 Console.WriteLine(stack.Peek()); 12 Console.WriteLine(stack.Count); 13 Console.WriteLine(stack.Pop()); 14 Console.WriteLine(stack.Count); 15 Console.ReadLine(); 16 17 } 18 }
运行结果:
顺序栈和链栈都成功了。
top初始值为-1或者是0,这都是什么和什么啊
top初始值为-1:
当你存储元素之后,top++,这时候top一直是指向栈顶元素的,这样做的好处是,栈的个数是top,而且stack[top]直接就是栈顶元素。缺点是调用Push时要Push(++top),栈的个数也是top+1.
top初始值为0:
top初始值为0的好处呢,就是Push的话直接Push(top),然后再top++;和栈的元素个数是top。稍微麻烦的是栈顶元素是stack[top-1].
其实top的初始值是-1还是0无关紧要,按照自己的习惯来就好,我是更倾向于top=-1;
顺序栈像一个只有一端开口的数组一样,链栈是怎么回事呀?
你可以把链栈理解为一个一个节点Node链接起来了,一个节点应该包括两部分,data和next.data里面装的是本节点的数据,next里面存储的是上一个节点的
链栈是这样进行的
标签:
原文地址:http://www.cnblogs.com/yunquan/p/4889029.html