队列很像列表(List),只不过不能按照任意索引来访问或删除指定的项。向队列里增加一个对象时,需要使用enqueue进行队。它会把最新入队的放入队尾。出队时使用dequeue,它会返回队头的对象,同时把它从队伍里面移出,此时队头会变为它之后的一项。
class QueueAndStact{
Queue<string> myQueue;
public void OptionQueue()
{
myQueue = new Queue<string>();//创建队列对象
//【入队enqueue】添加队列内容像队列增加四项。
myQueue.Enqueue("First Line");
myQueue.Enqueue("Second Line");
myQueue.Enqueue("Third Line");
myQueue.Enqueue("Last Line");
//查看队列第一项内容,但不从队列移出
string myLook = myQueue.Peek();
//查看队列有几项
int FHowMany = myQueue.Count;
//【出队dequeue】按照先进先出的规则进行出队
string firstOut = myQueue.Dequeue();
string secondOut = myQueue.Dequeue();
string thirdOut = myQueue.Dequeue();
//查看队列有几项
int LHowMany = myQueue.Count;
//清空队列
myQueue.Clear();
//查看清空后的队列有几项
int AfterClearHowMany = myQueue.Count;
//进行结果输出
Console.WriteLine("查看队列第一项:{0}", myLook);
Console.WriteLine("查看此时队列有几项:{0}", FHowMany);
Console.WriteLine("出队列第一项:{0}", firstOut);
Console.WriteLine("出队列第二项:{0}", secondOut);
Console.WriteLine("出队列第三项:{0}", thirdOut);
Console.WriteLine("查看此时队列有几项:{0}", LHowMany);
Console.WriteLine("查看清空后队列有几项:{0}", AfterClearHowMany);
}
}
栈与队列非常相似,但是有一个非常大的区别。每个项都要压入(Push)栈,要从栈中取出一项时只能从栈顶弹(Pop)出最新压入的一项。就像你把一打羽毛球放入球筒里,需要拿时就会取出最后一个放进去的。(按照常理,你要非要从另一头取我也没办法。)
class QueueAndStack{
Stack<string> myStack;//声明栈引用
public void OptionStack()
{
myStack = new Stack<string>();//创建栈对象
//【压栈Push】向栈压入四项。
myStack.Push("First Line");
myStack.Push("Second Line");
myStack.Push("Third Line");
myStack.Push("Last Line");
//查看栈顶内容,但不出栈
string myLook = myStack.Peek();
//查看现在栈里有几项
int FHowMany = myStack.Count;
//【出栈Pop】弹出栈顶的内容
string firstOut = myStack.Pop();
string secondeOut = myStack.Pop();
string thirdOut = myStack.Pop();
//查看现在栈里有几项
int LHowMany = myStack.Count;
//清空栈
myStack.Clear();
//查看现在栈里有几项
int afterClearStack = myStack.Count;
//输出结果
Console.WriteLine("查看栈顶:{0}", myLook);
Console.WriteLine("查看栈里有几项:{0}", FHowMany);
Console.WriteLine("第一个出栈:{0}", firstOut);
Console.WriteLine("第二个出栈:{0}", secondeOut);
Console.WriteLine("第三个出栈:{0}", thirdOut);
Console.WriteLine("查看此时栈里有几项:{0}", LHowMany);
Console.WriteLine("查看清空后栈里有几项:{0}", afterClearStack);
}
}
列表比较适合在需要随时取出数据和对数据操作的的情况下使用。比如一场淘汰赛,会淘汰分数最低的玩家。
队列比较适合有排队等待规则的情况下使用,先来先服务。比如,超市收银台排队。
栈比较适合随时使用最新的数据情况下使用。比如,一落凳子,你肯定会拿取最上面的一个。
你可能会觉得,栈和队列都可以使用列表实现,而Stack和Queue只是让你少写了几行代码。确实,我都这样感觉的。我觉得队列就想我当时学C时链表的尾加法,而栈像是头加法。
在C#中由于List、Queue、Stack都实现了IEnumerable接口,因而他们可以互相转换。
当你在创建他们时,把你需要转换的对象作为参数传入他们的构造函数中,就会获得一摸一样的数据,不过这时你创建的是一个副本,也就是说你会创建一个新的对象。当你修改和操作原始对象时不会对其他对象产生影响。如下代码展示。
public void tarnListQueueStack()
{
myStack = new Stack<string>();//创建栈对象
//【压栈Push】向栈压入四项。
myStack.Push("First Line");
myStack.Push("Second Line");
myStack.Push("Third Line");
myStack.Push("Last Line");
List<string> myList = new List<string>(myStack);//将mystack复制到myList
myQueue = new Queue<string>(myStack);//将myStack复制到myQueue
Stack<string> atherStack = new Stack<string>(myStack);//将myStack复制到新的atherStack
int FirstStackCount = myStack.Count;//查看执行pop前原始栈有几项
//对myStack操作,验证会不会对其他复制的对象产生影响
string myStackPop = myStack.Pop();
int stackCount = myStack.Count;//查看一次出栈后的mystack的栈里还有几项
int listCount = myList.Count;//查看list长度
int queueCount = myQueue.Count;//查看queue长度
int atherStackCount = atherStack.Count;//查看新的栈有几项
Console.WriteLine("原始栈执行出栈操作前栈有{0}项", FirstStackCount);
Console.WriteLine("一次出栈后的mystack的栈里还有{0}项", stackCount);
Console.WriteLine("list里还有{0}项", listCount);
Console.WriteLine("queue里还有{0}项", queueCount);
Console.WriteLine("新的栈有{0}项", atherStackCount);
}
从输出结果可以看出,对原始的栈myStack进行一次出栈操作后不会影响到其他对象。这时候可能还有一个疑虑,就是以它为参数复制的对象里面项的顺序是怎么存的。是否还会按照每个类型的特点读取之后在写入。下面上代码测试
public void tarnListQueueStack()
{
myStack = new Stack<string>();//创建栈对象
//【压栈Push】向栈压入四项。
myStack.Push("First Line");
myStack.Push("Second Line");
myStack.Push("Third Line");
myStack.Push("Last Line");
List<string> myList = new List<string>(myStack);//将mystack复制到myList
myQueue = new Queue<string>(myStack);//将myStack复制到myQueue
Stack<string> atherStack = new Stack<string>(myStack);//将myStack复制到新的atherStack
int FirstStackCount = myStack.Count;//查看执行pop前原始栈有几项
//对myStack操作,验证会不会对其他复制的对象产生影响
//string myStackPop = myStack.Pop();
int stackCount = myStack.Count;//查看一次出栈后的mystack的栈里还有几项
int listCount = myList.Count;//查看list长度
int queueCount = myQueue.Count;//查看queue长度
int atherStackCount = atherStack.Count;//查看新的栈有几项
/*Console.WriteLine("原始栈执行出栈操作前栈有{0}项", FirstStackCount);
Console.WriteLine("一次出栈后的mystack的栈里还有{0}项", stackCount);
Console.WriteLine("list里还有{0}项", listCount);
Console.WriteLine("queue里还有{0}项", queueCount);
Console.WriteLine("新的栈有{0}项", atherStackCount);*/
Console.WriteLine("开始输出myStack:");
OutputContent(myStack);
Console.WriteLine("");
Console.WriteLine("开始输出myList:");
OutputContent(myList);
Console.WriteLine("");
Console.WriteLine("开始输出myQueue:");
OutputContent(myQueue);
Console.WriteLine("");
Console.WriteLine("开始输出atherStack:");
OutputContent(atherStack);
Console.WriteLine("");
}
public void OutputContent(IEnumerable<string> enumerable)
{
int count = 1;
foreach(string str in enumerable)
{
Console.WriteLine("第{0}项:{1}",count, str);
count++;
}
Console.WriteLine("集合输出结束");
}
输出结果是
可以看出就算是复制也需要遵循每个类型的规则。List列表和Queue队列,进行循环时都是先入先出。然鹅输出和myStack内容一样,说明myStack作为参数时,还是会按照栈的先入后出的规则来读取,然后转换为指定的类型。从ahterStack和myStack结果相反进一步验证了进行foreach循环时还是要先入后出。从代码里也可以看出用他们都实现的IEnumerable
接口做参数,可以轻易的让们都能使用这个函数进行循环输出。
根据这个信息在往后推下,如果需要将一个List列表反序除了使用Reverse()方法外还可以使用栈来实现。如下代码
Console.WriteLine("反序前的myList:");
OutputContent(myList);
Console.WriteLine("");
Stack<string> temp = new Stack<string>(myList);
myList = new List<string>(temp);
Console.WriteLine("反序后的myList:");
OutputContent(myList);
Console.WriteLine("");
输出结果
-------------------------------------------------------------------------------------------
最后修改于2020/04/16
每天进步一点点!