队列与栈 #

一、Queue队列 #

1.1 队列特点 #

  • 先进先出(FIFO)
  • 入队Enqueue,出队Dequeue
  • 查看队首Peek

1.2 创建队列 #

csharp
var queue1 = new Queue<int>();
var queue2 = new Queue<int>(10);
var queue3 = new Queue<int>(new[] { 1, 2, 3, 4, 5 });

1.3 入队与出队 #

csharp
var queue = new Queue<string>();

queue.Enqueue("第一个");
queue.Enqueue("第二个");
queue.Enqueue("第三个");

string first = queue.Dequeue();
string second = queue.Dequeue();

1.4 查看队首 #

csharp
var queue = new Queue<int>();
queue.Enqueue(1);
queue.Enqueue(2);

int front = queue.Peek();
int count = queue.Count;

1.5 其他操作 #

csharp
var queue = new Queue<int>(new[] { 1, 2, 3, 4, 5 });

bool contains = queue.Contains(3);
int[] array = queue.ToArray();
queue.Clear();

1.6 遍历队列 #

csharp
var queue = new Queue<string>();
queue.Enqueue("张三");
queue.Enqueue("李四");
queue.Enqueue("王五");

foreach (var item in queue)
{
    Console.WriteLine(item);
}

二、Stack#

2.1 栈特点 #

  • 后进先出(LIFO)
  • 入栈Push,出栈Pop
  • 查看栈顶Peek

2.2 创建栈 #

csharp
var stack1 = new Stack<int>();
var stack2 = new Stack<int>(10);
var stack3 = new Stack<int>(new[] { 1, 2, 3, 4, 5 });

2.3 入栈与出栈 #

csharp
var stack = new Stack<string>();

stack.Push("第一个");
stack.Push("第二个");
stack.Push("第三个");

string top1 = stack.Pop();
string top2 = stack.Pop();

2.4 查看栈顶 #

csharp
var stack = new Stack<int>();
stack.Push(1);
stack.Push(2);

int top = stack.Peek();
int count = stack.Count;

2.5 其他操作 #

csharp
var stack = new Stack<int>(new[] { 1, 2, 3, 4, 5 });

bool contains = stack.Contains(3);
int[] array = stack.ToArray();
stack.Clear();

2.6 遍历栈 #

csharp
var stack = new Stack<string>();
stack.Push("张三");
stack.Push("李四");
stack.Push("王五");

foreach (var item in stack)
{
    Console.WriteLine(item);
}

三、PriorityQueue优先队列(.NET 6+) #

3.1 创建优先队列 #

csharp
var pq = new PriorityQueue<string, int>();

pq.Enqueue("低优先级", 3);
pq.Enqueue("高优先级", 1);
pq.Enqueue("中优先级", 2);

string highest = pq.Dequeue();
string next = pq.Dequeue();

3.2 自定义优先级 #

csharp
public class Task
{
    public string Name { get; set; }
    public int Priority { get; set; }
}

var pq = new PriorityQueue<Task, int>();

pq.Enqueue(new Task { Name = "任务A", Priority = 3 }, 3);
pq.Enqueue(new Task { Name = "任务B", Priority = 1 }, 1);
pq.Enqueue(new Task { Name = "任务C", Priority = 2 }, 2);

while (pq.Count > 0)
{
    var task = pq.Dequeue();
    Console.WriteLine($"{task.Name}: 优先级{task.Priority}");
}

四、实战示例 #

4.1 消息队列 #

csharp
public class MessageQueue
{
    private readonly Queue<Message> _queue = new();
    private readonly object _lock = new();
    
    public void Send(Message message)
    {
        lock (_lock)
        {
            _queue.Enqueue(message);
            Monitor.Pulse(_lock);
        }
    }
    
    public Message Receive()
    {
        lock (_lock)
        {
            while (_queue.Count == 0)
            {
                Monitor.Wait(_lock);
            }
            return _queue.Dequeue();
        }
    }
    
    public int Count
    {
        get { lock (_lock) { return _queue.Count; } }
    }
}

public record Message(string Content, DateTime Timestamp);

4.2 任务调度 #

csharp
public class TaskScheduler
{
    private readonly PriorityQueue<Task, DateTime> _tasks = new();
    
    public void Schedule(Task task, DateTime executeAt)
    {
        _tasks.Enqueue(task, executeAt);
    }
    
    public void Schedule(Task task, TimeSpan delay)
    {
        Schedule(task, DateTime.Now.Add(delay));
    }
    
    public async Task RunAsync(CancellationToken cancellationToken = default)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            if (_tasks.TryPeek(out _, out var executeAt))
            {
                var delay = executeAt - DateTime.Now;
                if (delay <= TimeSpan.Zero)
                {
                    var task = _tasks.Dequeue();
                    await ExecuteTaskAsync(task);
                }
                else
                {
                    await Task.Delay(delay, cancellationToken);
                }
            }
            else
            {
                await Task.Delay(100, cancellationToken);
            }
        }
    }
    
    private async Task ExecuteTaskAsync(Task task)
    {
        Console.WriteLine($"执行任务:{task.Name}");
        await Task.CompletedTask;
    }
}

4.3 表达式求值 #

csharp
public static class ExpressionEvaluator
{
    public static double Evaluate(string expression)
    {
        var values = new Stack<double>();
        var operators = new Stack<char>();
        
        for (int i = 0; i < expression.Length; i++)
        {
            char c = expression[i];
            
            if (char.IsDigit(c))
            {
                double num = 0;
                while (i < expression.Length && char.IsDigit(expression[i]))
                {
                    num = num * 10 + (expression[i] - '0');
                    i++;
                }
                i--;
                values.Push(num);
            }
            else if (c == '(')
            {
                operators.Push(c);
            }
            else if (c == ')')
            {
                while (operators.Peek() != '(')
                {
                    values.Push(ApplyOperator(operators.Pop(), values.Pop(), values.Pop()));
                }
                operators.Pop();
            }
            else if (IsOperator(c))
            {
                while (operators.Count > 0 && Precedence(operators.Peek()) >= Precedence(c))
                {
                    values.Push(ApplyOperator(operators.Pop(), values.Pop(), values.Pop()));
                }
                operators.Push(c);
            }
        }
        
        while (operators.Count > 0)
        {
            values.Push(ApplyOperator(operators.Pop(), values.Pop(), values.Pop()));
        }
        
        return values.Pop();
    }
    
    private static bool IsOperator(char c) => c == '+' || c == '-' || c == '*' || c == '/';
    
    private static int Precedence(char op) => op switch
    {
        '+' or '-' => 1,
        '*' or '/' => 2,
        _ => 0
    };
    
    private static double ApplyOperator(char op, double b, double a) => op switch
    {
        '+' => a + b,
        '-' => a - b,
        '*' => a * b,
        '/' => a / b,
        _ => throw new ArgumentException($"未知运算符:{op}")
    };
}

4.4 浏览器历史记录 #

csharp
public class BrowserHistory
{
    private readonly Stack<string> _backStack = new();
    private readonly Stack<string> _forwardStack = new();
    private string _current;
    
    public void Visit(string url)
    {
        if (_current != null)
        {
            _backStack.Push(_current);
        }
        _current = url;
        _forwardStack.Clear();
    }
    
    public string Back()
    {
        if (_backStack.Count == 0)
            return null;
        
        _forwardStack.Push(_current);
        _current = _backStack.Pop();
        return _current;
    }
    
    public string Forward()
    {
        if (_forwardStack.Count == 0)
            return null;
        
        _backStack.Push(_current);
        _current = _forwardStack.Pop();
        return _current;
    }
    
    public string Current => _current;
    public bool CanGoBack => _backStack.Count > 0;
    public bool CanGoForward => _forwardStack.Count > 0;
}

五、性能对比 #

操作 Queue Stack List
添加 O(1) O(1) O(1)
删除 O(1) O(1) O(n)
查找 O(n) O(n) O(n)

六、总结 #

队列与栈要点:

数据结构 特点 主要方法
Queue FIFO Enqueue, Dequeue, Peek
Stack LIFO Push, Pop, Peek
PriorityQueue 优先级 Enqueue, Dequeue, Peek

下一步,让我们学习异常处理!

最后更新:2026-03-26