網(wǎng)站首頁 編程語言 正文
.Net為我們提供了眾多的泛型集合。比如,Stack<T>先進(jìn)后出,Queue<T>先進(jìn)先出,List<T>集合元素可排序,支持索引,LinkedList<T>,雙向鏈表的泛型實現(xiàn),不支持索引;ISet<T>不允許被復(fù)制,他有2個實現(xiàn),一個是HashSet<T>,不維持集合元素的排序,另一個是SortedSet<T>,支持集合元素的排序;IDictionary<TKey, TValue>是一個字典集合的泛型接口,SortedList<TKey,TValue>實現(xiàn)了IDictionary<TKey, TValue>,但同時也是集合,維持集合元素的排序,支持按鍵或按值索引。
本篇體驗Stack<T>的用法。
基本用法
Stack<T>是Stack的泛型實現(xiàn),提供了若干方法和屬性,比如入棧、出棧、查看棧頂元素,查看棧內(nèi)集合元素數(shù)量,等等。棧的最大特點是先進(jìn)后出,可以把棧想像成一堆疊起來的盤子,入棧就是把一個個盤子放到最上面,出棧就是從最上面把盤子拿掉。用法比較簡單:
class Program
{
static void Main(string[] args)
{
var customer1 = new Customer() {ID = 1, Name = "張三", Gender = "男"};
var customer2 = new Customer() { ID = 2, Name = "李四", Gender = "男" };
Stack<Customer> stackCustomers = new Stack<Customer>();
//入棧
stackCustomers.Push(customer1);
stackCustomers.Push(customer2);
//查看棧頂元素
Customer topCustomer = stackCustomers.Peek();
Console.WriteLine("棧頂元素是:" + topCustomer.Name);
//遍歷所有棧內(nèi)元素
foreach (var customer in stackCustomers)
{
Console.WriteLine("id is {0},name is {1}", customer.ID, customer.Name);
}
//出棧
Customer outCustomer = stackCustomers.Pop();
Console.WriteLine("正在出棧的是:" + outCustomer.Name);
Console.WriteLine("當(dāng)前棧內(nèi)元素數(shù)量為:" + stackCustomers.Count);
Console.ReadKey();
}
}
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
}
臨摹一個泛型Stack<T>?
泛型Stack類內(nèi)部維護(hù)這一個泛型數(shù)組和索引指針,且指針的初始位置是-1。
入棧就是把指針往前提一位,并把入棧元素賦值給該棧內(nèi)位置。另外,入棧要考慮是否達(dá)到容量上限,如果達(dá)到就要給數(shù)組擴(kuò)容。
出棧就是讓當(dāng)前棧位置的元素值為入棧類型的默認(rèn)值,并大指針后退一位。
獲取棧頂元素就是獲取棧當(dāng)前索引位置對應(yīng)的元素。
public class MyStack<T>
{
//維護(hù)T類型的數(shù)組
private T[] _elements;
protected T[] Elements
{
get { return _elements; }
set { _elements = value; }
}
public MyStack()
{
_capacity = 5;//初始值
Elements = new T[Capacity];
}
public MyStack(int capacity)
{
Capacity = capacity;
Elements = new T[Capacity];
}
//指針
private int _index = -1;
public int Index
{
get { return _index; }
set { _index = value; }
}
//容量
private int _capacity;
public int Capacity
{
get { return _capacity; }
set { _capacity = value; }
}
//長度=索引+1
public int Length
{
get { return Index + 1; }
}
//入棧
public void Push(T element)
{
if (this.Length == Capacity)
{
IncreaseCapacity();
}
Index++;
Elements[Index] = element;
}
//出棧
public T Pop()
{
if (this.Length < 1)
{
throw new InvalidOperationException("棧內(nèi)已空");
}
T element = Elements[Index];
//原先位置元素變成默認(rèn)值
Elements[Index] = default(T);
//索引減一
Index--;
return element;
}
//獲取棧頂元素
public T Peek()
{
if (this.Length < 1)
{
throw new InvalidOperationException("棧內(nèi)已空");
}
return Elements[Index];
}
private void IncreaseCapacity()
{
Capacity++;
Capacity *= 2;
//創(chuàng)建新的T類型數(shù)組
T[] newElements = new T[Capacity];
//把原先的數(shù)組復(fù)制到新的數(shù)組中來
Array.Copy(Elements, newElements, Elements.Length);
Elements = newElements;
}
}
現(xiàn)在,在客戶端,實施一系列的入棧和出棧操作。
static void Main(string[] args)
{
//創(chuàng)建泛型Stack實例
MyStack<int> myStack = new MyStack<int>();
//遍歷10次入棧
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i + "開始入棧");
myStack.Push(i);
Console.WriteLine("當(dāng)前棧的長度是:" + myStack.Length);
}
//遍歷10次出棧
for (int i = 0; i < 10; i++)
{
Console.WriteLine("當(dāng)前出棧的是" + myStack.Peek());
myStack.Pop();
Console.WriteLine("當(dāng)前棧的長度是:" + myStack.Length);
}
//所有出棧結(jié)束,再查看棧頂元素拋異常
try
{
myStack.Peek();
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.Message);
}
//所有出棧結(jié)束,再出棧拋異常
try
{
myStack.Pop();
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
其實,泛型Stack<T>的內(nèi)部也是維護(hù)著一個數(shù)組,數(shù)組的容量是動態(tài)變化的,這一點很像List<T>,就像這里提到的。
使用泛型Stack<T>實現(xiàn)"撤銷/重做"操作
首先,操作或撤銷操作是針對某種類型的撤銷或重做,提煉出一個接口。
public interface ICommand<T>
{
T Do(T input);
T Undo(T input);
}
假設(shè),這里想實現(xiàn)對整型數(shù)的"撤銷/重做"操作。
public class AddIntCommand : ICommand<int>
{
private int _value;
public int Value
{
get { return _value; }
set { _value = value; }
}
public AddIntCommand()
{
_value = 0;
}
public AddIntCommand(int value)
{
_value = value;
}
//執(zhí)行操作
public int Do(int input)
{
return input + _value;
}
//撤銷操作
public int Undo(int input)
{
return input - _value;
}
}
接下來,需要一個泛型類來管理所有撤銷或操作命令,把這些命令放在Stack<ICommand<T>>泛型集合中。
//使用泛型Stack實現(xiàn)撤銷或重做
public class UndoRedoStack<T>
{
private Stack<ICommand<T>> _undo;//有關(guān)撤銷的泛型stack
private Stack<ICommand<T>> _redo;//有關(guān)重做的泛型stack
public UndoRedoStack()
{
Reset();
}
//記錄撤銷的數(shù)量
public int UndoCount
{
get { return _undo.Count; }
}
//記錄重做的數(shù)量
public int RedoCount
{
get { return _redo.Count; }
}
//恢復(fù)到出廠設(shè)置
public void Reset()
{
_undo = new Stack<ICommand<T>>();
_redo = new Stack<ICommand<T>>();
}
//執(zhí)行操作
public T Do(ICommand<T> cmd, T input)
{
T output = cmd.Do(input);
//把剛才的命令放入有關(guān)撤銷的stack中
_undo.Push(cmd);
//一旦啟動一個新命令,有關(guān)重做的stack清空
_redo.Clear();
return output;
}
//撤銷操作
public T Undo(T input)
{
if (_undo.Count > 0)
{
//出棧
ICommand<T> cmd = _undo.Pop();
T output = cmd.Undo(input);
_redo.Push(cmd);
return output;
}
else
{
return input;
}
}
//重做操作
public T Redo(T input)
{
if (_redo.Count > 0)
{
ICommand<T> cmd = _redo.Pop();
T output = cmd.Do(input);
_undo.Push(cmd);
return output;
}
else
{
return input;
}
}
}
最后,在客戶端按如下調(diào)用:
static void Main(string[] args)
{
UndoRedoStack<int> intCalulator = new UndoRedoStack<int>();
int count = 0;
count = intCalulator.Do(new AddIntCommand(10), count);
count = intCalulator.Do(new AddIntCommand(20), count);
Console.WriteLine("第一次計算的值為:{0}",count);
//執(zhí)行撤銷操作一次
count = intCalulator.Undo(count);
Console.WriteLine("第二次計算的值為:{0}",count);
Console.ReadKey();
}
原文鏈接:https://www.cnblogs.com/darrenji/p/4523483.html
相關(guān)推薦
- 2023-02-02 Go并發(fā)與鎖的兩種方式該如何提效詳解_Golang
- 2022-06-13 C#多線程之Parallel類的用法_C#教程
- 2022-11-26 Python?Django教程之模板的使用_python
- 2024-02-29 UNI-APP項目在引用官方提供的Uni-App-Demo實例中的組件時應(yīng)該注意的問題
- 2022-04-14 解決Mac環(huán)境下zsh: command not found:
- 2022-05-22 Nginx設(shè)置HTTPS的方法步驟_nginx
- 2023-01-14 Go?Map并發(fā)沖突預(yù)防與解決_Golang
- 2022-06-09 ASP.NET?Core配置和管理Web主機(jī)_基礎(chǔ)應(yīng)用
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支