首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 使用雙向鏈結清單 模擬 瀏覽器 前進/後退 歷史記錄

     編輯:關於C#

瀏覽器歷史記錄的核心行為:線性瀏覽時尾端新增、**後退移動游標**、**前進移動游標**、**後退後新增新網址會截斷未來歷史**。`LinkedList` 完美對應此模型:節點雙向鏈結、O(1) 插入/刪除、游標 (`LinkedListNode`) 直接對應「目前頁面」。本文提供完整 `HistoryManager` 實作。

核心邏輯

  • `Add(url)`:若目前非尾端 → 移除目前節點之後所有節點 (截斷未來) → 在頭端 (或尾端) 插入新節點 → 更新游標。
  • `Back()`:游標移至 `Current.Next` (較舊)。
  • `Forward()`:游標移至 `Current.Previous` (較新)。
  • `CanBack` / `CanForward`:檢查游標鄰接節點是否存在。

完整實作

using System;
using System.Collections.Generic;

public class HistoryEntry
{
    public string Url { get; set; }
    public string Title { get; set; }
    public string Html { get; set; } // 可選:快取內容離線檢視
    public DateTime VisitedAt { get; } = DateTime.Now;
}

public class HistoryManager
{
    private readonly LinkedList _list = new();
    private LinkedListNode _current;
    private readonly int _maxCount;

    public HistoryManager(int maxCount = 100) => _maxCount = maxCount;

    public HistoryEntry Current => _current?.Value;

    public bool CanBack => _current?.Next != null;
    public bool CanForward => _current?.Previous != null;

    /// 新增歷史 (瀏覽新頁面)
    public void Add(HistoryEntry entry)
    {
        // 連續重複網址不重複記錄
        if (_current != null && _current.Value.Url.Equals(entry.Url, StringComparison.OrdinalIgnoreCase))
            return;

        // 後退後新增:截斷未來歷史 (Current 之後的節點)
        if (_current != null && _current.Previous != null)
        {
            var toRemove = _current.Previous;
            while (toRemove != null)
            {
                var next = toRemove.Previous;
                _list.Remove(toRemove);
                toRemove = next;
            }
        }

        // 限制最大筆數:移除最舊 (尾端)
        if (_maxCount > 0 && _list.Count >= _maxCount)
            _list.RemoveLast();

        // 插入頭端 (最新)
        _current = new LinkedListNode(entry);
        _list.AddFirst(_current);
    }

    public HistoryEntry Back()
    {
        if (!CanBack) return null;
        _current = _current.Next;
        return _current.Value;
    }

    public HistoryEntry Forward()
    {
        if (!CanForward) return null;
        _current = _current.Previous;
        return _current.Value;
    }

    public IEnumerable GetAll() => _list; // 最新在前
}

UI 整合範例 (WinForm/WPF 通用)

private readonly HistoryManager _history = new(50);

private void Navigate(string url)
{
    // 1. 實際導航 (WebBrowser.Navigate / WebView2.CoreWebView2.Navigate)
    // 2. 導航完成後記錄
    _history.Add(new HistoryEntry { Url = url, Title = GetTitle() });
    UpdateNavButtons();
}

private void BtnBack_Click(object sender, EventArgs e)
{
    var entry = _history.Back();
    if (entry != null) LoadEntry(entry);
    UpdateNavButtons();
}

private void BtnForward_Click(object sender, EventArgs e)
{
    var entry = _history.Forward();
    if (entry != null) LoadEntry(entry);
    UpdateNavButtons();
}

private void UpdateNavButtons()
{
    btnBack.Enabled = _history.CanBack;
    btnForward.Enabled = _history.CanForward;
}

關鍵細節

場景處理
重複網址`Add` 開頭檢查 `_current.Value.Url` 忽略大小寫比較
最大筆數建構函式 `maxCount` 參數,超過移除 `RemoveLast()` (最舊)
序列化儲存`_list.Select(n => n.Value).ToList()` 序列化 JSON/XML,還原時重建 `LinkedList` 並定位 `_current`
多標籤頁每個 Tab 獨立一個 `HistoryManager` 實例
效能所有操作 O(1),記憶體開銷僅節點物件

替代資料結構比較

結構優點缺點適合度
LinkedList雙向、O(1) 插刪、游標天然對應無索引存取、記憶體碎片★★★★★ 最佳
List + index索引快、記憶體緊湊截斷未來需 `RemoveRange` O(n)、插入頭端 O(n)★★★☆☆ 可接受
兩個 Stack (back/forward)概念直觀無法直接實現「後退後新增截斷未來」需額外邏輯★★☆☆☆ 較麻煩

結語

`LinkedList` 以節點雙向鏈結完美映射瀏覽器歷史「游標 + 截斷未來」語意,代碼簡潔、效能最優。封裝為 `HistoryManager` 後,UI 僅需呼叫 `Add`/`Back`/`Forward` 並綁定 `CanBack`/`CanForward` 即可獲得完整體驗。若需持久化,序列化 `LinkedList` 節點序列並記錄 `_current` 索引即可還原。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved