堆栈:反转字符串、河内塔问题
队列: 呼叫中心单顾问、呼叫中心多顾问
优先级队列Priority queues: 呼叫中心优先级支持
// 第三章 stacks and queues ///
// 1.1 ReverseWords 反转字符串
!ESREVER S'TEL
static void Main(string[] args)
{
Stack<char> chars = new Stack<char>();
foreach (char c in "LET'S REVERSE!")
{
chars.Push(c);
}
while (chars.Count > 0)
{
Console.Write(chars.Pop());
}
Console.WriteLine();
Console.ReadLine();
}
/// 1.2 Tower of Hanoi 河内塔
FROM TO AUXILIARY
==========
============
==============
================
================== == ====
==================== ======== ======
Number of moves: 9
Number of discs: 10
/* HanoiTower.cs 河内塔类 */
using System;
using System.Collections.Generic;
namespace HanoiTowers
{
public class HanoiTower //河内塔
{
public int DiscsCount { get; private set; } //总盘数
public int MovesCount { get; private set; } //总移动次数
public Stack<int> From { get; private set; }
public Stack<int> To { get; private set; }
public Stack<int> Auxiliary { get; private set; }
public event EventHandler<EventArgs> MoveCompleted; //移动完成事件处理器
//构造函数
public HanoiTower(int discs)
{
DiscsCount = discs;//总盘数
From = new Stack<int>();
To = new Stack<int>();
Auxiliary = new Stack<int>();
for (int i = 1; i <= discs; i++)
{
int size = discs - i + 1;
From.Push(size);//初始化From 堆栈
}
}
//开始移动
public void Start()
{
Move(DiscsCount, From, To, Auxiliary);
}
//移动 递归移动
public void Move(int discs, Stack<int> from, Stack<int> to, Stack<int> auxiliary)
{
if (discs > 0)
{
Move(discs - 1, from, auxiliary, to);//将discs-1 个盘子 先放在辅助棒子auxiliary上
to.Push(from.Pop());//把from最底下的取出 放在to上
MovesCount++;//总移动次数
MoveCompleted?.Invoke(this, EventArgs.Empty); //完成搬运一次触发可视化
Move(discs - 1, auxiliary, to, from);//将辅助棒子auxiliary上的discs-1个盘子放到 to上
}
}
}
}
/* Main 程序 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace HanoiTowers
{
class Program
{
private const int DISCS_COUNT = 10;//盘数
private const int DELAY_MS = 250;//延迟时间
private static int _columnSize = 30;
static void Main(string[] args)
{
_columnSize = Math.Max(6, GetDiscWidth(DISCS_COUNT) + 2);// 每个堆栈的列数
HanoiTower algorithm = new HanoiTower(DISCS_COUNT);//构造河内塔
algorithm.MoveCompleted += Algorithm_Visualize;//完成一次搬运事件绑定处理方法
Algorithm_Visualize(algorithm, EventArgs.Empty);//调用一次算法可视化
algorithm.Start(); //开始移动
Console.ReadLine();
}
//没完成一次搬运触发可视化更新
private static void Algorithm_Visualize(object sender, EventArgs e)
{
Console.Clear();
HanoiTower algorithm = (HanoiTower)sender;//获取河内塔对象
if (algorithm.DiscsCount <= 0) { return; }
char[][] visualization = InitializeVisualization(algorithm);//初始化河内塔可视化数据
PrepareColumn(visualization, 1, algorithm.DiscsCount, algorithm.From);
PrepareColumn(visualization, 2, algorithm.DiscsCount, algorithm.To);
PrepareColumn(visualization, 3, algorithm.DiscsCount, algorithm.Auxiliary);
Console.WriteLine(Center("FROM") + Center("TO") + Center("AUXILIARY")); //先输出每个堆栈的居中标题
DrawVisualization(visualization);
Console.WriteLine();
Console.WriteLine($"Number of moves: {algorithm.MovesCount}");//总移动次数
Console.WriteLine($"Number of discs: {algorithm.DiscsCount}");
Thread.Sleep(DELAY_MS);
}
//初始化河内塔可视化数据 二维字符数组 为空格
private static char[][] InitializeVisualization(HanoiTower algorithm)
{
char[][] visualization = new char[algorithm.DiscsCount][]; //DiscsCount 层
for (int y = 0; y < visualization.Length; y++)//遍历每一层
{
visualization[y] = new char[_columnSize * 3]; //初始化每一层
for (int x = 0; x < _columnSize * 3; x++)
{
visualization[y][x] = ' ';//每个数据位空格
}
}
return visualization;
}
//准备列
private static void PrepareColumn(char[][] visualization, int column, int discsCount, Stack<int> stack)
{
int margin = _columnSize * (column - 1);//第几列左边界
for (int y = 0; y < stack.Count; y++)//准备堆栈的每行数据
{
int size = stack.ElementAt(y);//第y个盘的尺寸
int row = discsCount - (stack.Count - y);//确定盘所在行
int columnStart = margin + discsCount - size;//盘左边界
int columnEnd = columnStart + GetDiscWidth(size);// 盘右边界
for (int x = columnStart; x <= columnEnd; x++) //
{
visualization[row][x] = '=';
}
}
}
//输出堆栈数据
private static void DrawVisualization(char[][] visualization)
{
for (int y = 0; y < visualization.Length; y++)
{
Console.WriteLine(visualization[y]);//输出每层字符串数组
}
}
//每列居中输出字符串 FROM TO AUXILIARY
private static string Center(string text)
{
int margin = (_columnSize - text.Length) / 2;
return text.PadLeft(margin + text.Length).PadRight(_columnSize);
}
//获取盘宽度
private static int GetDiscWidth(int size)
{
return 2 * size - 1;
}
}
}
// 2.1 无优先级的呼叫中心 队列
[09:30:52] Call #1 from 1234 is answered by Marcin.
[09:30:59] Call #1 from 1234 is ended by Marcin.
[09:30:59] Call #2 from 5678 is answered by Marcin.
[09:31:08] Call #2 from 5678 is ended by Marcin.
[09:31:08] Call #3 from 1468 is answered by Marcin.
[09:31:11] Call #3 from 1468 is ended by Marcin.
[09:31:11] Call #4 from 9641 is answered by Marcin.
[09:31:19] Call #4 from 9641 is ended by Marcin.
/*Main 程序*/
class Program
{
static void Main(string[] args)
{
Random random = new Random();
CallCenter center = new CallCenter();
center.Call(1234);
center.Call(5678);
center.Call(1468);
center.Call(9641);
while (center.AreWaitingCalls())
{
IncomingCall call = center.Answer("Marcin");//取出呼叫进行应答
Log($"Call #{call.Id} from {call.ClientId} is answered by {call.Consultant}.");
Thread.Sleep(random.Next(1000, 10000));
center.End(call);//结束呼叫
Log($"Call #{call.Id} from {call.ClientId} is ended by {call.Consultant}.");
}
Console.ReadLine();
}
private static void Log(string text)
{
Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss")}] {text}");
}
}
/* CallCenter 呼叫中心类 */
public class CallCenter
{
private int _counter = 0;
public Queue<IncomingCall> Calls { get; private set; }
public CallCenter()
{
Calls = new Queue<IncomingCall>();
}
public void Call(int clientId)
{
IncomingCall call = new IncomingCall()
{
Id = ++_counter,
ClientId = clientId,
CallTime = DateTime.Now
};
Calls.Enqueue(call);
}
public IncomingCall Answer(string consultant)
{
if (Calls.Count > 0)
{
IncomingCall call = Calls.Dequeue();
call.Consultant = consultant;
call.StartTime = DateTime.Now;
return call;
}
return null;
}
public void End(IncomingCall call)
{
call.EndTime = DateTime.Now;
}
public bool AreWaitingCalls()
{
return Calls.Count > 0;
}
}
/* 来电类*/
public class IncomingCall //来电
{
public int Id { get; set; }
public int ClientId { get; set; }
public DateTime CallTime { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string Consultant { get; set; }
public bool IsPriority { get; set; }
}
/ 3.1 呼叫中心 优先级: callcenterpriority
[08:52:27] Call #2 from 5678 is answered by Marcin / Mode: priority.
[08:52:35] Call #2 from 5678 is ended by Marcin.
[08:52:35] Call #4 from 9641 is answered by Marcin / Mode: priority.
[08:52:38] Call #4 from 9641 is ended by Marcin.
[08:52:38] Call #1 from 1234 is answered by Marcin / Mode: normal.
[08:52:48] Call #1 from 1234 is ended by Marcin.
[08:52:48] Call #3 from 1468 is answered by Marcin / Mode: normal.
[08:52:56] Call #3 from 1468 is ended by Marcin.
/* 呼叫中心类 添加nuget包 OptimizedPriorityQueue */
using Priority_Queue;
using System;
namespace CallCenterPriority
{
public class CallCenter //呼叫中心
{
private int _counter = 0;
public SimplePriorityQueue<IncomingCall> Calls { get; private set; } //来电(优先级队列)
public CallCenter() //构造函数:实例化来电队列
{
Calls = new SimplePriorityQueue<IncomingCall>();
}
//增加来电
public void Call(int clientId, bool isPriority = false)
{
IncomingCall call = new IncomingCall()
{
Id = ++_counter,
ClientId = clientId,
CallTime = DateTime.Now,
IsPriority = isPriority
};
Calls.Enqueue(call, isPriority ? 0 : 1);
}
//开始处理来电
public IncomingCall Answer(string consultant)
{
if (Calls.Count > 0)
{
IncomingCall call = Calls.Dequeue();
call.Consultant = consultant;
call.StartTime = DateTime.Now;
return call;
}
return null;
}
//结束处理来电
public void End(IncomingCall call)
{
call.EndTime = DateTime.Now;
}
//等待的来电数
public bool AreWaitingCalls()
{
return Calls.Count > 0;
}
}
}
/*Main 程序 */
static void Main(string[] args)
{
Random random = new Random();
CallCenter center = new CallCenter();
center.Call(1234);
center.Call(5678, true);
center.Call(1468);//
center.Call(9641, true);
while (center.AreWaitingCalls())
{
IncomingCall call = center.Answer("Marcin");//处理来电
Log($"Call #{call.Id} from {call.ClientId} is answered by {call.Consultant} / Mode: {(call.IsPriority ? "priority" : "normal")}.");
Thread.Sleep(random.Next(1000, 10000));
center.End(call);//结束处理来电
Log($"Call #{call.Id} from {call.ClientId} is ended by {call.Consultant}.");
}
Console.ReadLine();
}
private static void Log(string text)
{
Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss")}] {text}");
}
}
// 3.2 并行执行 CallCenterMany 三个顾问线程池线程 应答 1个随机增加呼叫的线程
[09:22:34] Incoming call from 5491, waiting in the queue: 1
[09:22:34] Call #1 from 5491 is answered by Marcin.
[09:22:37] Call #1 from 5491 is ended by Marcin.
[09:22:37] Incoming call from 8784, waiting in the queue: 1
[09:22:37] Call #2 from 8784 is answered by James.
[09:22:40] Call #2 from 8784 is ended by James.
[09:22:41] Incoming call from 7664, waiting in the queue: 1
[09:22:41] Call #3 from 7664 is answered by Olivia.
[09:22:44] Call #3 from 7664 is ended by Olivia.
[09:22:45] Incoming call from 5008, waiting in the queue: 1
[09:22:45] Call #4 from 5008 is answered by Olivia.
[09:22:47] Incoming call from 5727, waiting in the queue: 1
[09:22:47] Call #5 from 5727 is answered by Marcin.
[09:22:49] Incoming call from 6093, waiting in the queue: 1
[09:22:49] Call #6 from 6093 is answered by James.
[09:22:52] Call #4 from 5008 is ended by Olivia.
[09:22:54] Incoming call from 7678, waiting in the queue: 1
[09:22:54] Call #7 from 7678 is answered by Olivia.
[09:22:55] Call #5 from 5727 is ended by Marcin.
[09:22:56] Incoming call from 3204, waiting in the queue: 1
[09:22:56] Call #8 from 3204 is answered by Marcin.
[09:22:57] Call #6 from 6093 is ended by James.
[09:22:57] Incoming call from 2799, waiting in the queue: 1
[09:22:57] Call #9 from 2799 is answered by James.
[09:22:58] Incoming call from 5693, waiting in the queue: 1
[09:22:59] Incoming call from 8044, waiting in the queue: 2
[09:23:00] Call #7 from 7678 is ended by Olivia.
[09:23:01] Call #10 from 5693 is answered by Olivia.
[09:23:02] Call #8 from 3204 is ended by Marcin.
[09:23:02] Call #11 from 8044 is answered by Marcin.
……
/* Main 程序 */
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CallCenterMany
{
class Program
{
static void Main(string[] args)
{
CallCenter center = new CallCenter();
Parallel.Invoke(//尽可能并行执行提供的每个操作
() => CallersAction(center), //1个呼叫线程
() => ConsultantAction(center, "Marcin", ConsoleColor.Red),//3个顾问应答线程
() => ConsultantAction(center, "James", ConsoleColor.Yellow),
() => ConsultantAction(center, "Olivia", ConsoleColor.Green));
Console.ReadLine();
}
//呼叫着动作
private static void CallersAction(CallCenter center)
{
Random random = new Random();
while (true)
{
int clientId = random.Next(1, 10000);
int waitingCount = center.Call(clientId);//增加随机客户端clientId的呼叫,并返回总呼叫数
Log($"Incoming call from {clientId}, waiting in the queue: {waitingCount}");
Thread.Sleep(random.Next(1000, 5000));
}
}
//顾问动作
private static void ConsultantAction(CallCenter center, string name, ConsoleColor color)
{
Random random = new Random();
while (true)
{
IncomingCall call = center.Answer(name);//尝试取出一个呼叫,开始应答
if (call != null)
{
Console.ForegroundColor = color;
Log($"Call #{call.Id} from {call.ClientId} is answered by {call.Consultant}.");
Console.ForegroundColor = ConsoleColor.Gray;
Thread.Sleep(random.Next(1000, 10000));
center.End(call);//结束应答
Console.ForegroundColor = color;
Log($"Call #{call.Id} from {call.ClientId} is ended by {call.Consultant}.");
Console.ForegroundColor = ConsoleColor.Gray;
Thread.Sleep(random.Next(500, 1000));
}
else
{
Thread.Sleep(100);
}
}
}
private static void Log(string text)
{
Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss")}] {text}");
}
}
}
/*呼叫中心 略有改变*/
public class CallCenter
{
private int _counter = 0;
public ConcurrentQueue<IncomingCall> Calls { get; private set; }
public CallCenter()
{
Calls = new ConcurrentQueue<IncomingCall>();
}
public int Call(int clientId)
{
IncomingCall call = new IncomingCall()
{
Id = ++_counter,
ClientId = clientId,
CallTime = DateTime.Now
};
Calls.Enqueue(call);
return Calls.Count;
}
public IncomingCall Answer(string consultant)
{
if (Calls.Count > 0 && Calls.TryDequeue(out IncomingCall call))//尝试取出一个呼叫进行应答
{
call.Consultant = consultant;
call.StartTime = DateTime.Now;
return call;
}
return null;
}
public void End(IncomingCall call)
{
call.EndTime = DateTime.Now;
}
public bool AreWaitingCalls()
{
return Calls.Count > 0;
}
}