数据结构系列:单链表[C#]

今天来写一下 单链表 的总结

这次我学链表的方式是,先自己写一个C#版本的链表,来看看自己的思维是否正确,然后再看视频进行修正。从中发现了不少问题。

首先说一下链表的特点

  1. 动态的内存管理,初始不会固定内存,随着结点的增加不断增加
  2. 增加 和 删除的擅长比较方便,不需要像顺序表一样移动很多元素
  3. 查找的时候效率低,因为需要从结点去一个个寻找

然后说一下自己的问题

  1. 对循环语句不够细心,不要太马虎
  2. 对指针学的还不够,需要找机会重学
  3. 对链表结构还是需要多复习一下
  4. get set方法没有理解透彻

下面就先写一个C#中的结点Node类。
//我原本是直接想每个结点都 设置好前后的连接,类似双向链表
//这里写了四个构造函数,

 class Node<T>//结点类 作为链表的核心元素
    {
        private T CurData;//存放数据
        private Node<T> next;//指向下一个结点的链条
        public Node(T data)
        {
            CurData = data;
            next = null;
        }
        public Node(T data, Node<T> node)
        {
            next = node;
            CurData = data;
        }  //第三种是只需要传递一个引用 不需要数据
        public Node(Node<T> node)
        {
            next = node;
        }
        public Node()
        {
            CurData = default(T);
            next = null;
        }
        //给属性提供 getset方法
        public T Data
        {
            get
            {
                return CurData;
            }
            set
            {
                CurData = value;
            }
        }
        public Node<T> Next
        {
            get
            {
                return next;
            }
            set
            {
                next = value;
            }
        }
    }

然后就是传统C#的接口
//但是这次跟顺序表有一些不一样
在于我添加是增加了两个方法,因为链栈的特点跟顺序表不同,
他的ADD跟Insert方法是不会发生矛盾的,
所以有两种插入方式

  1. 一个是按照顺序加在链表的最后。
  2. 一个是按照index进行随意的插入。
interface LinkedList<T>
    {
        int GetLenth();
        bool isEmty();
        void Clear();
        void ListInsert(T item, int index);
        void ListAdd(T item);
        void ListDelete(int index);
        T GetEle(int index);//就是GetEle
        int Locate(T value);
        T this[int index] { get; }
        T PreElem(int index);
        T NextElem(int index);
        void ListTraverse();
      }

然后就是实现方法
//这次实现的关键点是

  1. 熟悉单链表的操作形式(找到对应的结点,进行操作)
  2. 增加 插入 删除 寻找 的方法跟以往的数据结构不一样
  3. T this[int index] {get;} 这个方法 我是第一次写好像//要记住
  4. 确定好这个index这里用的是 0 1 2 3 4
 class MyList<T> : LinkedList<T>
    {
        private Node<T> head;//最初的头结点,所有方法的开始
        private int ListLength;//我自己进行计数的属性

        public T this[int index]
        {  //第一个点  用这个方法来寻找 【特定位置】的元素
            get
            {   Node<T> temp = head;
                for (int i = 1; i <= index; i++)
                {  //假设寻找的0,开始便不成立,头结点0的数据继续
                   //假设寻找的1,满足条件,遍历一次,返回1的数据
                   //假设寻找的2,满足条件,遍历两次,不满足了。退出
                    temp = temp.Next;
                }
                return temp.Data;
            }
        }
        public MyList()//构造函数 不需要size
        {
            head = null;
            ListLength = 0;//置空
        }
        public void ListAdd(T item)
        {
            Node<T> newNode = new Node<T>(item);//新结点存好数据
            if (head == null)
            {//如果头结点 为空 //这个就是头结点
                head = newNode;
                ListLength++;
            }
            else
            {//不然就把新来的结点放到链表的尾部
             //要访问道链表的尾结点(利用死循环)
                Node<T> temp = head;
                while (true)
                {
                    if (temp.Next != null)
                    {//如果 头结点的下一个 结点不为空
                        temp = temp.Next;
                        //结点内不为空 临时的变量会变成下一个
                    }
                    else
                    {
                        break;//直到某个结点后面为空 退出循环
                    }
                }
                ListLength++;
                temp.Next = newNode;//把新来的结点放到尾部。
            }
        }
        
        public void ListInsert(T item, int index)
        {   //制作一个新的结点
            //插入的时候head不能为空
            Node<T> newNode = new Node<T>(item);
            if (index == 0)//插入到头结点
            {
                newNode.Next = head;//原来的头结点还有 链表后移
                head = newNode; //新的头结点
            }
            else
            {
                Node<T> temp = head;//从头开始寻找
                for (int i = 1; i < index-1; i++)
                {
                    temp = temp.Next;
                }
                Node<T> preNode = temp;  
                Node<T> currntNode = temp.Next;
                preNode.Next = newNode;//正式插入的位置。
                newNode.Next = currntNode;
                ListLength++;

                //当插入位置为1 ,不进入循环,当前结点被找到,插入
                //当插入位置为2,循环一次,退出,插入
                //当插入位置为3时,循环两次,退出,插入
            }
        }
        public T PreElem(int index)
         {
                 return this[index - 1];//方便的方法
         }
        public T PreElem(int index)     //之前练手用的
        {       
            if(!isEmty())//首先不能为空
            {
                if(index != 0)
                {
                    Node<T> temp = head;//找头
                    for (int i = 1; i <= index-1 ; i++)
                    {
                        temp = temp.Next;
                    }
                    return temp.Data;
                    //如果为1 不循环,直接输出1的前结点head;
                    //如果是2 循环一次 直接输出2的前结点1;
                }
                else
                {
                    return default(T);
                }}
            else { return default(T); }
            }
            
        
        public void Clear()
        {
            head = null;//头节点为空 所有引用消失
        }

        public bool isEmty()
        {
            return head == null;//头结点无法引用
        }
        public int GetLenth()
        {
              return ListLength;
        }
        public void ListDelete(int index)
        {
            if(index ==0)
            {
                head = head.Next;//头结点直接连后面的那个
                ListLength--;
            }
            else
            {
                Node<T> temp = head;
                for (int i = 1; i <= index-1; i++)
                {
                    temp = temp.Next;//通过这个循环找到前结点
                }
                Node<T> preNode = temp;
                Node<T> nextNode = temp.Next.Next;
                preNode.Next = nextNode;
                ListLength--;
            }
        }

        public T GetEle(int index)
        {
            return this[index];
        }

        public int Locate(T value)
        {
            Node<T> temp = head;
            if(temp==null)
            {
                return -1;
            }
            else
            {
                int index = 0;
                while(true)
                {
                    if(temp.Data.Equals(value))
                    {
                        return index;
                    }
                    else
                    {
                        if(temp.Next!=null)
                        {
                            temp = temp.Next;
                        }
                        else
                        { break; }//没有满足情况
                    }
                }
                return -1;
            }
        }
    }

就这样,这样的一个链表就完成了,我最大的问题还是不够熟练,还是需要反复多看一次这些代码。(尤其了循环语句都弄错几次)

本来想一次性把C++的链表也po出来,但是感觉自己还是没有掌握的很好,就放弃了,继续加油。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值