• c#单链表


    链表是有序列表,它在内存中是存储如下:

     

     

    上图的表格来模拟链表的结构,其中每一行为一个节点(以第一行举例110,a2,180)。

    • ‘data域’用来存放数据
    • ‘next域’用来指向下一个节点。
    • ‘头指针(也成为头节点)’,150是指向表格中第五行的‘地址为150’的a1节点。而‘next域’110指向 a2节点

     

    小结

    • 1.链表是以节点方式来存储,是链式存储。
    • 2.每个节点包含‘data域’,‘next域’。
    • 3.如图:发现链表的各个节点不一定是连续存放的。
    • 4.链表分带‘头节点’,和‘没有带头节点的’链表,根据实际的需求来确定。

     

    单链表介绍

    单链表(带头节点)逻辑结构示意图如下:

     

     

    最后一个节点的‘next域’为空。

     

    单链表的应用

    使用带head头的单项链表实现,对数据的增删改查操作。

    • 第一种方法在添加数据时,直接添加到链表的尾部
    • 第二种方法在添加数据时,根据排序将数据插入到指定位置。(如果这个位置被占用,则添加失败并给出提示)

    代码实现思路:

     

     

    添加(创建)

    • 1.先创建一个head头节点,作用就是表示单链表的头
    • 2.后面我们每加一个节点,就直接假如到链表的最后

    遍历:

    • 1.通过一个辅助变量遍历,帮助遍历整个单链表

     

    数据结构定义

    public class DataNode
    {
      public int Id { get; set; }
    
      public string Name { get; set; }
    
      public string NikeName { get; set; }
    
      public DataNode Node { get; set; }
    
      public DataNode(int id, string name, string nikeName)
      {
          Id = id;
          Name = name;
          NikeName = nikeName;
      }
    
      public override string ToString()
      {
          return $"DataNode[{Id},{Name},{NikeName}]";
      }
    }

     

    public class SingleLinkedList
    {
      /*
        * 定义一个头节点,保证不要改动它因为被修改之后就找不到链表的最顶端。
        * 先初始化一个头节点,头节点不要动,不存放具体的数据
        */
      private DataNode head = new DataNode(0,"","");
    
      /*
        * 当不考虑编号的顺序时
        * 1.找到当前链表的最后节点
        * 2.将最后这个节点的next域指向新的节点即可
        */
      public void Add(DataNode node)
      {
          //因为head节点不能改动,因此我们需要一个辅助变量辅助遍历temp
          DataNode temp = head;
          //遍历链表,找到最后
          while (true)
          {
              //找到链表的最后
              if (temp.NextNode == null)
              {
                  break;
              }
    
              //如果没有找到则后移
              temp = temp.NextNode;
          }
          //当推出while循环时,temp就指向了链表的最后
          //将最后这个节点的next指向新的节点
          temp.NextNode = node;
      }
    
      //显示链表(遍历)
      public void List()
      {
          if (head.NextNode == null)
          {
              Console.WriteLine("链表为空");
              return;
          }
          //因为头节点不能改动,因此我们需要一个辅助变量来遍历
          DataNode temp = head.NextNode;
          while (true)
          {
              //判断是否到链表最后
              if (temp == null)
              {
                  break;
              }
              //输出节点信息
              Console.WriteLine(temp);
              //将next后移,一定记住需要后移。不然就是死循环
              temp = temp.NextNode;
          }
      }
    }

    1.添加

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          list.Add(node1);
          list.Add(node2);
          list.Add(node3);
          list.Add(node4);
          list.List();
      }
    }

     

     

    如果当我们把list.add的添加顺序修改一下。会发现:

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          list.Add(node1);
          list.Add(node4);
          list.Add(node2);
          list.Add(node3);
          list.List();
      }
    }

     

     

    目前这种写法是按照添加顺序来显示的,add时并没有考虑编号。接下来将继续演示:

    • 不管如何顺序的add,都要按照顺序排名(指定位置)来添加节点数据。

     

    分析

    需要按照变化的顺序添加

    • 1.首先找到新添加的节点的位置,时通过辅助变量(指针);通过遍历搞定
    • 2.新的节点next域=temp.next
    • 3.将temp.next = 新的节点

    代码如下:

      /*
        * 第二种方式在添加节点时,根据排名将节点插入到指定位置
        * 如果有这个排名,则添加失败并提示
        */
      public void AddNodeByOrder(DataNode node)
      {
          //因为头节点不能东,因此我们仍然通过一个辅助变量来帮助找到添加的位置
          //因为单链表,因此我们找的tmep是位于添加位置的前一个节点,否则插入不了
          DataNode temp = head;
          bool flag = false;//标识添加的编号是否存在,默认为false
          while (true)
          {
              if (temp.NextNode == null)
              {
                  //说明temp已经在链表的最后
                  break;
              }
    
              if (temp.NextNode.Id > node.Id)
              {
                  //位置找到,就在temp的后面插入
    
                  break;
              }
              else if(temp.NextNode.Id == node.Id)
              {
                  //说明希望添加的datanode的编号已经存在
                  flag = true;//说明编号存在
                  break;
              }
              //后移,遍历当前的链表
              temp = temp.NextNode;
          }
          //判断flag的值
          if (flag)
          {
              //不能添加,说明编号已经存在
              Console.WriteLine($"准备插入的节点编号{node.Id}已经存在");
          }
          else
          {
              //插入到链表中,temp的后面
              node.NextNode = temp.NextNode;
              temp.NextNode = node;
          }
      }

    调用

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          /* list.Add(node1);
            list.Add(node4);
            list.Add(node2);
            list.Add(node3);*/
    
          list.AddNodeByOrder(node1);
          list.AddNodeByOrder(node4);
          list.AddNodeByOrder(node2);
          list.AddNodeByOrder(node3);
          list.List();
      }
    }

     

     

     

    然后我们再测试一下添加重复节点的效果:

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          /* list.Add(node1);
            list.Add(node4);
            list.Add(node2);
            list.Add(node3);*/
    
          list.AddNodeByOrder(node1);
          list.AddNodeByOrder(node4);
          list.AddNodeByOrder(node2);
          list.AddNodeByOrder(node3);
          list.AddNodeByOrder(node3);
          list.List();
      }
    }

     

     

    2.修改

     

      /*
        * 修改节点的信息,根据编号来修改,即编号不能改
        * 说明:
        * 1.根据NewDataNode的id来修改即可
        */
      public void Update(DataNode node)
      {
          //判断链表是否空
          if (head.NextNode == null)
          {
              Console.WriteLine("链表为空");
              return;
          }
          //找到需要修改的节点,根据id
          //先顶一个一个辅助变量
          DataNode temp = head.NextNode;
          bool flag = false;//表示是否找到该节点
          while (true)
          {
              if (temp == null)
              {
                  break;//已经遍历完链表
              }
    
              if (temp.Id == node.Id)
              {
                  //找到了
                  flag = true;
                  break;
              }
              temp = temp.NextNode;
          }
    
          //根据flag判断是否找到要修改的节点
          if (flag)
          {
              temp.Name = node.Name;
              temp.NikeName = node.NikeName;
          }
          else
          {
              //没有找到
              Console.WriteLine($"没有找到编号的节点,不能修改{node.Id}");
          }
      }

     

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          /* list.Add(node1);
            list.Add(node4);
            list.Add(node2);
            list.Add(node3);*/
    
          list.AddNodeByOrder(node1);
          list.AddNodeByOrder(node4);
          list.AddNodeByOrder(node2);
          list.AddNodeByOrder(node3);
    
          list.List();
          Console.WriteLine();
          //修改节点
          var newNode = new DataNode(2, "Juster", "Justerter!!!");
          list.Update(newNode);
          list.List();
      }
    }

     

     

    3.删除

    从单链表删除一个节点的思路

    • 1.先找到需要删除的节点的,前一个节点temp
    • 2.temp.next = temp.next.next
    • 3.被删除的节点,将不会有其它引用指向,会被垃圾回收机制回收

     

     

    删除1号

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          /* list.Add(node1);
            list.Add(node4);
            list.Add(node2);
            list.Add(node3);*/
    
          list.AddNodeByOrder(node1);
          list.AddNodeByOrder(node4);
          list.AddNodeByOrder(node2);
          list.AddNodeByOrder(node3);
    
          list.List();
          Console.WriteLine();
          //修改节点
          //var newNode = new DataNode(2, "Juster", "Justerter!!!");
          //list.Update(newNode);
    
          //删除节点
          list.Delete(1);
          list.List();
      }
    }

     

     

     

    全部删除

    class Program
    {
      static void Main(string[] args)
      {
          var node1 = new DataNode(1,"法外狂徒张三","三哥");
          var node2 = new DataNode(2, "隔壁李四", "四哥");
          var node3 = new DataNode(3, "楼下王五", "五哥");
          var node4 = new DataNode(4, "同学老六", "六哥");
    
          var list = new SingleLinkedList();
          /* list.Add(node1);
            list.Add(node4);
            list.Add(node2);
            list.Add(node3);*/
    
          list.AddNodeByOrder(node1);
          list.AddNodeByOrder(node4);
          list.AddNodeByOrder(node2);
          list.AddNodeByOrder(node3);
    
          list.List();
          Console.WriteLine();
          //修改节点
          //var newNode = new DataNode(2, "Juster", "Justerter!!!");
          //list.Update(newNode);
    
          //删除节点
          list.Delete(1);
          list.Delete(4);
          list.Delete(2);
          list.Delete(3);
          list.List();
      }
    }

     

     

  • 相关阅读:
    vmware 搭建内外网分开的三台centos7.9虚拟机
    CentOS 7 搭建frp内网穿透服务端
    CentOS 7 搭建frp内网穿透客户端
    Redis设计与实现读书笔记
    easyui 下拉框绑定成功之后,又无法显示
    easyui 实现后一个弹框向前一个弹框传值
    学会这七个Python GUI图形界面化库,就没有做不出来的界面!超有用!
    最新!用Python免费连接附近WiFi教程!没有我蹭不到的网!
    用Python实现九九乘法表的几种方式,入门必备案例!超级简单!
    为了每天准时看到冰冰,我用Python写了个自动提醒脚本,美滋滋!
  • 原文地址:https://www.cnblogs.com/justzhuzhu/p/15866451.html
Copyright © 2020-2023  润新知