数据结构之基于无序链表的集合和映射

使用代码实现自定义的集合类

   #region 链表类
    public class MyLinkedList<T>
    {
        //当前链表类记录这个链表的头部类
        private Node head;
        //链表的节点数量
        private int N;
        public MyLinkedList()
        {
            N = 0;
            //因为一开始链表没有元素,所以头部节点指向空。
            head = null;
        }



        /// <summary>
        /// 链表节点数量
        /// </summary>
        public int Count
        {
            get { return N; }
        }
        /// <summary>
        /// 链表是否为空
        /// </summary>
        public bool IsEmpty
        {
            get { return N == 0; }
        }

        public void Add(int index, T e)
        {
            if (index < 0 || index > N)
            {
                throw new Exception("非法索引");
            }

            if (index == 0)
            {
                //新的头部节点
                //1:添加新节点
                //Node node = new Node(e);
                ////2:将新添加的头结点的箭头指向原先头结点
                //node.next = head;
                ////3:现在的头结点信息赋给类的头结点字段,记录下来。
                //head = node;
                //其实上面三步可以结合到一步中,
                head = new Node(e, head);
            }
            else
            {
                //添加非头部节点
                //1.需要找到插入位置的上一个节点,对于链表来说就要从头部节点开始一步一步的查找了
                Node pre = head;
                //一步一步遍历找到前一个节点信息
                for (int i = 0; i < index - 1; i++)
                {
                    pre = pre.next;
                }
                //1:将前一节点的下一节点信息赋值给当前节点对象的下一节点字段,目的是为了让当前节点能够链接到下一节点
                Node node = new Node(e);
                node.next = pre.next;
                //2:前一节点链接到新插入的节点 此时链表已经重新完成
                pre.next = node;
                //上面代码也可以合成一句
                //   pre.next = new Node(e, pre.next);

            }
            //链表的元素加一
            N++;
        }

        public void AddFirst(T e)
        {
            Add(0, e);
        }

        public void AddLast(T e)
        {
            Add(N, e);
        }

        /// <summary>
        /// 节点类  不让外部知道此类,设为私有
        /// </summary>
        private class Node
        {
            //当前节点
            public T e;
            //当前节点的下一节点
            public Node next;
            public Node(T e, Node next)
            {
                this.e = e;
                this.next = next;
            }
            public Node(T e)
            {
                this.e = e;
            }

        }


        public T Get(int index)
        {
            if (index < 0 || index >= N)
            {
                throw new Exception("非法索引");
            }

            Node currentNode = head;//从头结点开始查找
            for (int i = 0; i < index; i++)
            {
                currentNode = currentNode.next;
            }

            return currentNode.e;
        }


        public T GetFirst()
        {
            return Get(0);
        }
        public T GetLast()
        {
            return Get(N - 1);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="index"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public void Set(int index, T e)
        {
            if (index < 0 || index >= N)
            {
                throw new Exception("非法索引");
            }

            Node currentNode = head;//从头结点开始查找
            for (int i = 0; i < index; i++)
            {
                currentNode = currentNode.next;
            }

            currentNode.e = e; ;
        }
        /// <summary>
        /// 查找链表中是否存在此元素
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public bool Contains(T e)
        {
            Node current = head;
            while (current != null)
            {
                if (current.e.Equals(e))
                {
                    return true;
                }

                current = current.next;
            }

            return false;
        }
        /// <summary>
        /// 可以重写tostring打印方法
        /// 打印出链表信息
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder stringBuilder = new StringBuilder();
            Node cur = head;
            while (cur != null)
            {
                stringBuilder.Append(cur.e + "->");
                cur = cur.next;
            }
            stringBuilder.Append("null");
            return stringBuilder.ToString();

        }

        #region 删除节点

        public T Remove(int index)
        {
            if (index < 0 || index > N)
            {
                throw new Exception("非法索引");
            }

            if (index == 0)
            {
                Node delNode = head;
                //直接将原头部节点指向的下一节点的信息存储到头部节点的字段上,直接这样就能删除原头部节点了
                head = delNode.next;
                N--;
                return delNode.e;
            }
            else
            {
                Node pre = head;
                //找到删除节点的前一节点信息
                for (int i = 0; i < index - 1; i++)
                {
                    pre = pre.next;
                }
                Node delNode = pre.next;
                //1:z将前一节点的指向做更改
                pre.next = delNode.next;
                N--;
                return delNode.e;
            }
        }

        public T RemoveFirst()
        {
            return Remove(N);
        }

        #endregion
        #region 删除节点  根据值节点查找

        public void Remove(T e)
        {
            if (head == null)
            {
                return;
            }

            if (head.e.Equals(e))
            {
                //删除的是头结点
                head = head.next;
                N--;
            }
            else
            {
                Node current = head;
                Node pre = null;
                while (current != null)
                {
                    if (current.e.Equals(e))
                    {
                        break;
                    }

                    pre = current;
                    current = current.next;

                }

                if (current != null)
                {
                    pre.next = current.next.next;
                    N--;
                }
            }

        }

        #endregion
    }
    #endregion
View Code

 

    interface ISet<E>
    {
        int Count { get; }
        bool IsEmpty { get; }
        void Add(E e);
        void Remove(E e);
        bool Contains(E e);

    }
View Code
  class LinkedListISet<E> : ISet<E>
    {
        private MyLinkedList<E> list;
        public LinkedListISet()
        {
            list = new MyLinkedList<E>();
        }



        public int Count { get { return list.Count} }
        public bool IsEmpty { get { return list.IsEmpty } }
        /// <summary>
        /// 基于无序链表的集合的添加方法
        /// </summary>
        /// <param name="e"></param>
        public void Add(E e)
        {
            if (!list.Contains(e))
            {
                list.AddFirst(e);
            }
        }

        public bool Contains(E e)
        {
            return list.Contains(e);
        }

        public void Remove(E e)
        {
            list.Remove(e);
        }
    }
View Code

 

测试代码:

class Program
    {
        static void Main(string[] args)
        { 
            //假设words包含了很多单词
            List<string> words = new List<string>();
            LinkedListISet<string> linkedListISet = new LinkedListISet<string>();
            foreach (var item in words)
            {
                linkedListISet.Add(item); 
            } 

           Console.WriteLine(); 
        }

    }
View Code

 

从上面代码能看出来这个性能是很慢的,因为每次添加的时候都要看一下这个单词是否已经包含了,每次看是否包含的时候都要从链表的头到尾遍历一次。可以使用映射解决问题。

 

下面创建一个自定义的字典类:

    

   interface IDictionary<Key, Value>
    {
        int Count { get; }
        bool IsEmpty { get; }
        void Add(Key key, Value value);
        void Remove(Key key);
        bool ContainsKey(Key key);
        Value Get(Key key);
        void Set(Key key, Value value);

    }







/// <summary>
    /// 具有键值的链表类
    /// </summary>
    /// <typeparam name="Key"></typeparam>
    /// <typeparam name="Value"></typeparam>
    class LinkedListKeyValue<Key, Value>
    {
        /// <summary>
        /// 节点
        /// </summary>
        private class Node
        {
            public Key key;
            public Value value;
            public Node next;
            public Node(Key key, Value value, Node next)
            {
                this.key = key;
                this.value = value;
                this.next = next;
            }
            /// <summary>
            /// 重写输出
            /// </summary>
            /// <returns></returns>
            public override string ToString()
            {
                return key.ToString() + ":" + value.ToString();
            }

        }

        private Node head;
        public int N;
        public LinkedListKeyValue()
        {
            head = null;
            N = 0;
        }

        public int Count { get { return N; } }
        public bool IsEmpty { get { return N == 0; } }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private Node GetNode(Key key)
        {
            Node cur = head;
            while (cur != null)
            {
                if (cur.key.Equals(key))
                    return cur;

                cur = cur.next;
            }

            return null;
        }

        public void Add(Key key, Value value)
        {
            Node node = GetNode(key);
            if (node == null)
            {
                head = new Node(key, value, head);
            }

        }

        public bool Contains(Key key)
        {
            return GetNode(key) != null;
        }

        public Value Get(Key key)
        {
            Node node = GetNode(key);
            if (node == null)
            {
                throw new ArgumentException($"键{key}不存在");
            }
            else
            {
                return node.value;
            }

        }

        public void Set(Key key, Value value)
        {
            Node node = GetNode(key);
            if (node == null)
                throw new Exception();
            node.value = value;
        }
        public void Remove(Key key)
        {
            if (head == null)
            {
                return;
            }

            if (head.key.Equals(key))
            {
                //删除的是头结点
                head = head.next;
                N--;
            }
            else
            {
                Node current = head;
                Node pre = null;
                while (current != null)
                {
                    if (current.key.Equals(key))
                    {
                        break;
                    }

                    pre = current;
                    current = current.next;

                }

                if (current != null)
                {
                    pre.next = current.next.next;
                    N--;
                }
            }

        }

    }


    /// <summary>
    /// 实现自定义的字典类
    /// </summary>
    /// <typeparam name="Key"></typeparam>
    /// <typeparam name="Value"></typeparam>
    public class LinkedListDictionary<Key, Value> : IDictionary<Key, Value>
    {

        private LinkedListKeyValue<Key, Value> list;
        public LinkedListDictionary()
        {
            list = new LinkedListKeyValue<Key, Value>();
        }

        public int Count { get { return list.Count; } }

        public bool IsEmpty { get { return list.IsEmpty; } }

        public void Add(Key key, Value value)
        {
            list.Add(key, value);
        }

        public bool ContainsKey(Key key)
        {
            return list.Contains(key);
        }

        public Value Get(Key key)
        {
            return list.Get(key);
        }

        public void Remove(Key key)
        {
            list.Remove(key);
        }

        public void Set(Key key, Value value)
        {
            list.Set(key, value);
        }
    }
View Code

 

但是就算是这样性能还是很慢的,所以我们可以使用基于有序数组的集合和映射来解决这个问题,有时间再深入,简单来说就是查找元素这块是用二分查找算法实现的,所以比基于无序链表的集合和映射在查找元素方法上性能更强。

 

posted @ 2021-08-27 07:11  安静点--  阅读(38)  评论(0编辑  收藏  举报