數據結構之雙向鏈表--C#版

面試考察頻率:⭐⭐⭐⭐

什麼是雙向鏈表?

在單向鏈表的前提下,增加了前驅指針,可以跟輕鬆的訪問一個節點的前驅與後繼節點

雙向鏈表優缺點?

優點:可以更便捷的訪問一個節點的前驅與後繼。
缺點:需要佔用更多一些的內存。刪除節點操作變得更加複雜。

如何來實現?

構建思路如下
當前節點的next指向下一個節點。當前節點的pre指向上一個節點如此循環。(注:頭節點的pre始終指向最後一個節點,爲了方便遍歷,具體的在後面會講)。基本的樣子就入下圖所示(繪製粗糙0.0)

基礎結構表示:

        public class LinkedListNode
        {
            public LinkedListNode pre;
            public LinkedListNode next;
            public int val;
        }

初始化:

        private void InitList(int c, LinkedListNode node)
        {
            node = new LinkedListNode();
            node.pre = node;
            node.next = null;
            node.val = -1;
        }

就是創建一個頭節點,該節點不進行數據記錄只是爲了方便操作。初始只有一個節點時pre要指向自己。

尾插入:

public void Add_Back(LinkedListNode node, int x)
        {
            LinkedListNode tmp = node;
            while (tmp.next != null)
            {
                tmp = tmp.next;
            }
            LinkedListNode p = new LinkedListNode();
            p.next = null;
            p.pre = tmp;
            p.val = x;
 
            node.pre = p;
            tmp.next = p;
 
            m_length++;
        }

尾插入和單鏈表的尾插入基本相似,都要先遍歷找到最後一個節點。然後記得更新頭節點的pre指針,始終指向最後一個節點。

打印與反向打印:

        public void PrintList(LinkedListNode node)
        {
            LinkedListNode p = node;
            while (p.next != null)
            {
                Console.WriteLine(p.next.val);
                p = p.next;
            }
            Console.WriteLine();
        }
 
        public void ReversePrintList(LinkedListNode node)
        {
            LinkedListNode p = node.pre;
            while (p != node)
            {
                Console.WriteLine(p.val);
                p = p.pre;
            }
            Console.WriteLine();
        }

正向打印沒有什麼多說的,和單鏈表的打印一樣。

反向打印從頭節點開始,因爲頭節點的pre始終指向最後一個節點,所以也就是相當與從最後一個節點開始遍歷一樣,逐個走每個節點的pre域。當遍歷的pre域等於頭節點時表示遍歷完成。

刪除節點:

        public void DeleteValueAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode= FindNodeAsPosition(node, pos);
            
            if(pos==Length)//如果是尾節點的情況
            {
                Console.WriteLine("刪除的是尾節點");
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//如果不是尾巴節點的情況
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }

需要考慮是最後一個節點還是非最後一個節點。

如果爲最後一個節點要更新頭節點的pre,然後取到倒數第二個節點,把next與最後一個節點斷開。

如果不是最後一個節點要取得到要刪除節點的上一個節點,設置其next域斷開當前節點。然後取到要刪除節點的下一個節點,設置其pre域斷開當前節點。

完整代碼如下,更多數據C#數據結構源碼歡迎瀏覽我的倉庫:https://github.com/w199753/DataStructural-CSharp 最後附上完整代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace DataStructural
{
    public class DoubleLinkedList
    {
        private int m_length = 0;
        public int Length { get { return m_length; } }
 
        public class LinkedListNode
        {
            public LinkedListNode pre;
            public LinkedListNode next;
            public int val;
        }
 
        public void CreateList(int c, LinkedListNode node)
        {
            InitList(c, node);
            for (int i = 0; i < c; i++)
            {
                int x = int.Parse(Console.ReadLine().ToString());
                Add_Back(node, x);
            }
        }
        private void InitList(int c, LinkedListNode node)
        {
 
            node = new LinkedListNode();
            node.pre = node;
            node.next = null;
            node.val = -1;
        }
 
        /// <summary>
        /// 尾插入
        /// </summary>
        /// <param name="node"></param>
        /// <param name="x"></param>
        public void Add_Back(LinkedListNode node, int x)
        {
            LinkedListNode tmp = node;
            while (tmp.next != null)
            {
                tmp = tmp.next;
            }
            LinkedListNode p = new LinkedListNode();
            p.next = null;
            p.pre = tmp;//設置新節點的pre指向最後一個節點
            p.val = x;
 
            node.pre = p;//設置頭節點的pre域爲新節點
            tmp.next = p;//連接新節點
 
            m_length++;
        }
 
        /// <summary>
        /// 插入元素,要判斷實在尾部還是在身子部
        /// </summary>
        /// <param name="node"></param>
        /// <param name="pos"></param>
        /// <param name="x"></param>
        public void Insert(LinkedListNode node, int pos, int x)
        {
            LinkedListNode p = new LinkedListNode();
            if(pos==Length-1)
            {
                Add_Back(node, x);
            }
            else
            {
                LinkedListNode tNode = FindNodeAsPosition(node, pos);
                p.val = x;
                p.pre = tNode;
                p.next = tNode.next;
 
                tNode.next.pre = p;
                tNode.next = p;
            }
            m_length++;
        }
 
        public void PrintList(LinkedListNode node)
        {
            LinkedListNode p = node;
            while (p.next != null)
            {
                Console.WriteLine(p.next.val);
                p = p.next;
            }
            Console.WriteLine();
        }
 
        public void ReversePrintList(LinkedListNode node)
        {
            LinkedListNode p = node.pre;
            while (p != node)
            {
                Console.WriteLine(p.val);
                p = p.pre;
            }
            Console.WriteLine();
        }
 
        public LinkedListNode FindNodeAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode = node;
            int tPos = 1;
            while (tNode.next != null)
            {
                if (tPos == pos)
                {
                    Console.WriteLine("value is:" + tNode.next.val);
                    return tNode.next;
                } 
                tNode = tNode.next;
                tPos++;
            }
            return null;
        }
 
        public LinkedListNode FindNodeAsValue(LinkedListNode node, int val)
        {
            LinkedListNode tNode = node;
            while (tNode.next != null)
            {
                if (tNode.next.val == val) return tNode.next;
                tNode = tNode.next;
            }
            return null;
        }
 
        public int IndexOf(LinkedListNode node,int val)
        {
            int index = -1;
            int z = 0;
            LinkedListNode tNode = node;
            while (tNode.next != null)
            {
                if (tNode.next.val == val)
                {
                    index = z;
                    return index;
                }
                tNode = tNode.next;
                z++;
            }
            return index;
        }
 
        /// <summary>
        /// 刪除節點,要考慮最後一個和中間元素的情況。
        /// </summary>
        /// <param name="node"></param>
        /// <param name="pos"></param>
        public void DeleteValueAsPosition(LinkedListNode node, int pos)
        {
            LinkedListNode tNode= FindNodeAsPosition(node, pos);
            
            if(pos==Length)//如果是尾節點的情況
            {
                Console.WriteLine("刪除的是尾節點");
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//如果不是尾巴節點的情況
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }
 
        public void DeleteValueAsValue(LinkedListNode node,int value)
        {
            LinkedListNode tNode = FindNodeAsValue(node, value);
 
            int index = IndexOf(node, value);
 
            if (index==Length-1)//最後一個節點
            {
                node.pre = tNode.pre;
                tNode.pre.next = null;
            }
            else//不是最後一個節點
            {
                tNode.pre.next = tNode.next;
                tNode.next.pre = tNode.pre;
            }
            m_length--;
        }
 
        /// <summary>
        /// 清空所有節點
        /// </summary>
        /// <param name="node"></param>
        public void Clear(LinkedListNode node)
        {
            int len = Length;
            for (int i=1;i<=len;i++)
            {
                DeleteValueAsPosition(node, 1);
            }
        }
 
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章