C#栈
线性表、栈和队列这三种数据结构的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的操作不受限制,而栈和队列的操作受到限制。栈的操作只能在表的一端进行, 队列的插入操作在表的一端进行而其它操作在表的另一端进行,所以,把栈和队列称为操作受限的线性表。
栈(Stack)是操作限定在表的尾端进行的线性表。表尾由于要进行插入、删除等操作,所以,它具有特殊的含义,把表尾称为栈顶(Top) ,另一端是固定的,叫栈底(Bottom) 。当栈中没有数据元素时叫空栈(Empty Stack)。栈通常记为:S= (a 1 ,a 2 ,…,a n ),S是英文单词stack的第 1 个字母。a 1 为栈底元素,a n 为栈顶元素。这n个数据元素按照a 1 ,a 2 ,…,a n 的顺序依次入栈,而出栈的次序相反,a n 第一个出栈,a 1 最后一个出栈。所以,栈的操作是按照后进先出(Last In First Out,简称LIFO)或先进后出(First In Last Out,简称FILO)的原则进行的, 因此, 栈又称为LIFO表或FILO表。
栈的操作示意图如图所示。

栈的形式化定义为:栈(Stack)简记为 S,是一个二元组,
S = (D, R)
其中: D 是数据元素的有限集合;
R 是数据元素之间关系的有限集合。
由于栈只能在栈顶进行操作, 所以栈不能在栈的任意一个元素处插入或删除元素。因此,栈的操作是线性表操作的一个子集。栈的操作主要包括在栈顶插入元素和删除元素、取栈顶元素和判断栈是否为空等。与线性表一样,栈的运算是定义在逻辑结构层次上的,而运算的具体实现是建立在物理存储结构层次上的。因此,把栈的操作作为逻辑结构的一部分,而每个操作的具体实现只有在确定了栈的存储结构之后才能完成。
栈的接口定义如下所示。
public interface IStack<T>//栈的接口定义
{
int GetLength(); //求栈的长度
bool IsEmpty(); //判断栈是否为空
void Clear(); //清空操作
void Push(T item); //入栈操作
T Pop(); //出栈操作
T GetTop(); //取栈顶元素
}
用一片连续的存储空间来存储栈中的数据元素,这样的栈称为顺序栈(Sequence Stack)。类似于顺序表,用一维数组来存放顺序栈中的数据元素。
顺序栈类 SeqStack<T>的实现说明如下所示。
public class SeqStack<T> : IStack<T>//顺序栈类
{
private int max; //顺序栈的容量
private int top; //指示顺序栈的栈顶
private T[] data; //数组,用于存储顺序栈中的数据元素
public int Max
{
get { return max; }
set { max = value; }
}
public int Top
{
get { return top; }
}
public T this[int index]
{
get { return data[index]; }
set { data[index] = value; }
}
public SeqStack(int size)
{
data = new T[size];
max = size;
top = -1;
}
public int GetLength()
{
return top + 1;
}
public bool IsEmpty()
{
return top == -1;
}
public bool IsFull()
{
return top == max - 1;
}
public void Clear()
{
top = -1;
}
public void Push(T item)
{
if (IsFull())
{
Console.WriteLine("Stack is full");
return;
}
data[++top] = item;
}
public T Pop()
{
T tmp = default(T);
if (IsEmpty())
{
Console.WriteLine("Stack is empty");
return tmp;
}
tmp = data[top--];
return tmp;
}
public T GetTop()
{
if (IsEmpty())
{
Console.WriteLine("Stack is empty");
return default(T);
}
return data[top];
}
}
栈的另外一种存储方式是链式存储,这样的栈称为链栈(Linked Stack)。链栈通常用单链表来表示,它的实现是单链表的简化。所以,链栈结点的结构与单链表结点的结构一样,如图所示。由于链栈的操作只是在一端进行,为了操作方便,把栈顶设在链表的头部,并且不需要头结点。

把链栈看作一个泛型类,类名为 LinkStack<T>。LinkStack<T>类中有一个字段 top 表示栈顶指示器。由于栈只能访问栈顶的数据元素,而链栈的栈顶指示器又不能指示栈的数据元素的个数。所以,求链栈的长度时,必须把栈中的数据元素一个个出栈,每出栈一个数据元素,计数器就增加 1,但这样会破坏栈的结构。为保留栈中的数据元素, 需把出栈的数据元素先压入另外一个栈, 计算完长度后,再把数据元素压入原来的栈。但这种算法的空间复杂度和时间复杂度都很高,所以, 以上两种算法都不是理想的解决方法。 理想的解决方法是 LinkStack<T>类增设一个字段 num 表示链栈中结点的个数。
链栈类 LinkStack<T>的实现说明如下所示。
public class Node<T>//链栈结点类
{
private T data;
private Node<T> next;
public T Data
{
get { return data; }
set { data = value; }
}
public Node<T> Next
{
get { return next; }
set { next = value; }
}
public Node(T val, Node<T> node)
{
data = val;
next = node;
}
public Node(T val)
{
data = val;
next = null;
}
public Node(Node<T> node)
{
data = default(T);
next = node;
}
public Node()
{
data = default(T);
next = null;
}
}
public class LinkStack<T> : IStack<T> //链栈类的实现
{
private Node<T> top; //栈顶指示器
private int num; //栈中结点的个数
public Node<T> Top
{
get { return top; }
set { top = value; }
}
public int Num
{
get { return num; }
set { num = value; }
}
public LinkStack()
{
top = null;
num = 0;
}
public int GetLength()
{
return num;
}
public bool IsEmpty()
{
return top == null && num == 0;
}
public void Clear()
{
top = null;
num = 0;
}
public void Push(T item)
{
Node<T> node = new Node<T>(item);
if (top == null)
{
top = node;
}
else
{
top.Next = node;
top = node;
}
++num;
}
public T Pop()
{
if (IsEmpty())
{
Console.WriteLine("Stack is empty!");
return default(T);
}
Node<T> p = top;
top = top.Next;
return p.Data;
}
public T GetTop()
{
if (IsEmpty())
{
Console.WriteLine("Stack is empty!");
return default(T);
}
return top.Data;
}
}
C#栈的更多相关文章
- 通往全栈工程师的捷径 —— react
腾讯Bugly特约作者: 左明 首先,我们来看看 React 在世界范围的热度趋势,下图是关键词“房价”和 “React” 在 Google Trends 上的搜索量对比,蓝色的是 React,红色的 ...
- Java 堆内存与栈内存异同(Java Heap Memory vs Stack Memory Difference)
--reference Java Heap Memory vs Stack Memory Difference 在数据结构中,堆和栈可以说是两种最基础的数据结构,而Java中的栈内存空间和堆内存空间有 ...
- duang~免费的学习视频来啦:学霸君之全栈测试
学霸君向童鞋们推荐一款 同名学霸学习 视频教程 重点是完全免费收看学习噢!!! 今天 学霸君推荐腾讯课堂的学霸君之全栈测试 复制下方链接至腾讯课堂中报名学习 https://ke.qq.com/cou ...
- [数据结构]——链表(list)、队列(queue)和栈(stack)
在前面几篇博文中曾经提到链表(list).队列(queue)和(stack),为了更加系统化,这里统一介绍着三种数据结构及相应实现. 1)链表 首先回想一下基本的数据类型,当需要存储多个相同类型的数据 ...
- BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 8748 Solved: 3835[Submi ...
- BZOJ 4453: cys就是要拿英魂![后缀数组 ST表 单调栈类似物]
4453: cys就是要拿英魂! Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 90 Solved: 46[Submit][Status][Discu ...
- BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2326 Solved: 1054[Submit][Status ...
- .NET全栈开发工程师学习路径
PS:最近一直反复地看博客园以前发布的一条.NET全栈开发工程师的招聘启事,觉得这是我看过最有创意也最朴实的一个招聘启事,更为重要的是它更像是一个技术提纲,能够指引我们的学习和提升,现在转载过来与各位 ...
- Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解
用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息 ...
- 匹夫细说C#:不是“栈类型”的值类型,从生命周期聊存储位置
0x00 前言: 匹夫在日常和别人交流的时候,常常会发现一旦讨论涉及到“类型”,话题的热度就会立马升温,因为很多似是而非.或者片面的概念常常被人们当做是全面和正确的答案.加之最近在园子看到有人翻译的& ...
随机推荐
- 斐讯k1路由器刷Breed BootLoader(不死UBoot)教程
刷入Breed BootLoader: 因为这个K1路由器可以开启telnet服务,所以此处刷Breed可以不使用编程器刷Flash芯片的方法进行. 1.打开K1路由器的Telnet服务. 电脑通过有 ...
- NoSQL生态系统——一致性RWN协议,向量时钟,gossip协议监测故障
13.5 一致性 在NoSQL中,通常有两个层次的一致性:第一种是强一致性,既集群中的所有机器状态同步保持一致.第二种是最终一致性,既可以允许短暂的数据不一致,但数据最终会保持一致.我们先来讲一下,在 ...
- 搭建一个分布式MongoDB鉴权集群
今天休假在家,测试并搭建了一个replica set shard MongoDB鉴权集群.replica set shard 鉴权集群中文资料比较少,本文是个人笔记,同时也希望对后来者有所帮助.本文仅 ...
- js Date 函数方法 和 移动端数字键盘调用
var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-???? ...
- RP4412开发板在Android系统编译生成ramdisk-uboot.img
荣品RP4412开发板在android系统编译的时候,怎么生成ramdisk-uboot.img生成流程分析: mkimage -A arm -O linux -T ramdisk -C none - ...
- dom事件与event对象总结
1 事件:就是文档或浏览器窗口中发生的一些特定的交互瞬间. tips:js和xhtml的交互是通过当用户或浏览器操作网页时发生的事件来处理的. 1.1 事件流:即事件的顺序. 事件 ...
- IO多路复用,实现多线程监听
服务端 import socket sk1 = socket.socket() sk1.bind(('127.0.0.1',8001)) sk1.listen() sk2 = socket.socke ...
- 对copy、mutableCopy理解
Objective - C 中有很多在日常项目中经常用到的常用代码,在这里着重的讲一下关于copy 和 mutableCopy 的区别以及相关用法. Objective - C 中可变对象和不可对象经 ...
- 深入replace
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. stringObject.replace(reg/str,str/replacement); 这里主 ...
- IHttpHandler防止图片链接被盗用
public class JpegHandler : IHttpHandler { public bool IsReusable { get { return true; } } public voi ...