链表(二):单向链表

一、什么是单向链表

在动态分配内存空间时,最常使用的就是“单向链表”(Single Linked List)。一个单向链表节点基本上是由两个元素,即数据字段和指针所组成,而指针将会指向下一个元素在内存中的位置,如下图所示:

在“单向链表”中,第一个节点是“链表头指针”,指向最后一个节点的指针设为NULL,表示它是“链表尾”,不指向任何地方。例如列表A={a、b、c、d、x},其单向链表的数据结构如下图所示:

由于单向链表中所有节点都知道节点本身的下一个节点在哪里,但是对于前一个节点却没有办法知道,所以在单向链表的各种操作中,“链表头指针”就显得相当重要,只要存在链表头指针,就可以遍历整个链表,进行加入和删除节点等操作。

注意:除非必要,否则不可移动链表头指针。

通常在其他程序设计语言中,如C或C++语言,是以指针(pointer)类型来处理链表类型的数据结构。由于在C#程序设计语言中没有指针类型,因此可以把链表声明为类(class)。例如要模拟链表中的节点,必须声明如下的Node类,这里使用泛型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 链表节点类
    /// </summary>
    public class Node<T>
    {
        /// <summary>
        /// 数据字段
        /// </summary>
        public T Data { get; set; }

        /// <summary>
        /// 指针 指向下一个元素
        /// </summary>
        public Node<T> Next { get; set; }

        /// <summary>
        /// 无参构造函数
        /// </summary>
        public Node()
        {
            // 赋默认值
            this.Data = default(T);
            this.Next = null;
        }

        /// <summary>
        /// 只传递数据字段的构造函数,指针默认为null
        /// </summary>
        /// <param name="value"></param>
        public Node(T value)
        {
            this.Data = value;
            this.Next = null;
        }

        /// <summary>
        /// 同时传递数据和指针的构造函数
        /// </summary>
        /// <param name="value"></param>
        /// <param name="next"></param>
        public Node(T value,Node<T> next)
        {
            this.Data = value;
            this.Next = next;
        }

        /// <summary>
        /// 只传递指针的构造函数
        /// </summary>
        /// <param name="next"></param>
        public Node(Node<T> next)
        {
            this.Next = next;
        }
    }
}

接着可以声明链表SingleLinkedList类,该类定义两个Node<T>类型的节点指针,分别指向链表的第一个节点和最后一个节点:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingleLinkedListDemo
{
    public class SingleLinkedList<T>
    {
        /// <summary>
        /// 头节点
        /// </summary>
        private Node<T> HeadNode;

        /// <summary>
        /// 尾节点
        /// </summary>
        private Node<T> LastNode;

        // 定义类中其它方法,增加节点、删除节点、移动节点等
    }
}

如果链表中的节点不只记录单一数值,例如每一个节点除了有指向下一个节点的指针字段外,还包括学生的姓名、学号、成绩,则其链表如下图所示:

如果是这种链表,我们可以先定义一个Student类,里面包括姓名、学号、成绩,然后Node节点里面使用泛型Node<Student>。下面我们以学生为例讲解如何创建一个单向链表。

1、建立单向链表

现在我们使用C#语言的链表处理以下学生的成绩问题。

首先我们必须声明节点的数据类型,让每一个节点包含一个数据,并且包含指向下一个节点的指针,使所有的数据都能被串在一起形成一个列表结构,最终链表如下图所示:

下面我们详细说明建立上图所示的单向链表的步骤:

1、建立一个新的节点,如图所示:

2、这时链表是空的,所以讲链表的first即last指针字段都指向新创建的节点newNode,如图所示:

3、建立另外一个新的节点,如图所示:

4、将上面的两个节点串起来,使用下面的代码:

last.next=newNode;
last=newNode;

如图所示:

5、重复上面的3、4步骤,将所有的节点都连接起来,最终链表结构如图所示:

由于列表中所有节点都知道节点本身的下一个节点在哪里,但是对于前一个节点却没有办法知道,所以“头节点”就显得非常重要。

无论如何,只要有头节点存在,就可以对整个列表进行遍历、加入、删除、查找等操作。而之前建立的节点若没有串接起来就会形成无人管理的节点,并一直占用内存空间。因此在建立列表时必须有一个列表指针指向头节点,并且在没有必要的情况下不可以移动列表首指针。

我们可以在程序中会声明Node类和SignleLinkedList类,在SignleLinkedList类中,定义了两个Node类型的节点指针,分别指向链表的第一个节点和最后一个节点。另外,该类中还需要声明下面的两个方法:

方法名称 功能描述
public bool IsEmpty() 用来判断当前的链表是否为空链表
public void Add(T item) 用来将指定的节点插入到当前的链表

下面我们以一个具体的例子来讲解如何创建一个单向链表。需求如下:

设计一个C#程序,可以让用户输入数据来添加学生数据节点,以建立一个单向链表。一共输入5位学生的成绩来建立单向链表,然后遍历单向链表中的每一个节点来打印输出学生的信息。

我们先建立Node节点类,这里使用泛型,利于扩展:

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 链表节点类
    /// </summary>
    public class Node<T>
    {
        /// <summary>
        /// 数据字段
        /// </summary>
        public T Data { get; set; }

        /// <summary>
        /// 指针 指向下一个元素
        /// </summary>
        public Node<T> Next { get; set; }

        /// <summary>
        /// 无参构造函数
        /// </summary>
        public Node()
        {
            // 赋默认值
            this.Data = default(T);
            this.Next = null;
        }

        /// <summary>
        /// 只传递数据字段的构造函数,指针默认为null
        /// </summary>
        /// <param name="value"></param>
        public Node(T value)
        {
            this.Data = value;
            this.Next = null;
        }

        /// <summary>
        /// 同时传递数据和指针的构造函数
        /// </summary>
        /// <param name="value"></param>
        /// <param name="next"></param>
        public Node(T value,Node<T> next)
        {
            this.Data = value;
            this.Next = next;
        }

        /// <summary>
        /// 只传递指针的构造函数
        /// </summary>
        /// <param name="next"></param>
        public Node(Node<T> next)
        {
            this.Next = next;
        }
    }
}

我们创建一个Student类,用来存放学生信息:

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 学生类
    /// </summary>
    public class Student
    {
        /// <summary>
        /// 学号
        /// </summary>
        public int Number { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 成绩
        /// </summary>
        public int Score { get; set; }

        public Student(int number,string name,int score)
        {
            Number = number;
            Name = name;
            Score = score;
        }
    }
}

最后创建SignleLinkedList类,代码如下:

using System.Collections.Generic;

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 单向链表类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SingleLinkedList<T>
    {
        /// <summary>
        /// 存放所有链表节点的集合
        /// </summary>
        public List<Node<T>> ListNode { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public SingleLinkedList()
        {
            ListNode = new List<Node<T>>();
        }

        /// <summary>
        /// 头节点
        /// </summary>
        private Node<T> HeadNode;

        /// <summary>
        /// 尾节点
        /// </summary>
        private Node<T> LastNode;

        /// <summary>
        /// 判断当前链表是否为空链表
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return HeadNode == null;
        }

        /// <summary>
        /// 插入节点
        /// </summary>
        public void AddNode(T item)
        {
            // 新建一个节点
            Node<T> newNode = new Node<T>(item);

            // 判断头节点是否为null,如果为null,那么新建的节点就是头节点,同时也是尾节点
            if (IsEmpty())
            {
                // 如果是空链表,则将头节点和尾节点都指向新建的节点
                HeadNode = newNode;
                LastNode = newNode;
            }
            else
            {
                // 尾节点的指针指向新建的节点
                // 新建的节点变为尾节点
                LastNode.Next = newNode;
                LastNode = newNode;
            }
            // 将新建的节点添加到集合中
            ListNode.Add(newNode);
        }
    }
}

在Main方法里面调用:

using System;
using System.Collections.Generic;

namespace SingleLinkedListDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int num;
            string name;
            int score;

            Console.WriteLine("请输入5位学生的成绩:");
            SingleLinkedList<Student> linkedList = new SingleLinkedList<Student>();
            for (int i = 0; i < 5; i++)
            {
                Console.Write("请输入学号:");
                num = int.Parse(Console.ReadLine());
                Console.Write("请输入姓名:");
                name = Console.ReadLine();
                Console.Write("请输入成绩:");
                score = int.Parse(Console.ReadLine());
                Student student = new Student(number: num, name: name, score: score);
                linkedList.AddNode(student);
                Console.WriteLine("----------------");
            }

            Console.WriteLine();
            Console.WriteLine("输出学生成绩信息");
            List<Node<Student>> list = linkedList.ListNode;
            foreach (var item in list)
            {
                Console.WriteLine($"学号: {item.Data.Number},姓名: {item.Data.Name},成绩: {item.Data.Score}");
                Console.WriteLine();
            }

            Console.ReadKey();
        }
    }
}

程序运行结果:

2、单向链表节点的删除

在单向链表类型的数据结构中,若要在链表中删除一个节点,则根据所删除节点的位置会有以下三种不同的情况。

1、删除链表的第一个节点

如果是删除链表中的第一个节点,只要把链表的头指针指向第二个节点即可,如图所示:

程序参考代码:

if(first.data == delNode.data)
    first=first.next;

2、删除链表内的中间节点

如果是删除链表内的中间节点,那么只要将删除节点的前一个节点的指针,指向要删除节点的下一个节点即可,如图所示:

程序参考代码:

3、删除链表的最后一个节点

如果是删除链表的最后一个节点,那么只要将指向最后一个节点的指针,直接指向null即可,如图所示:

程序参考代码

我们还是以上面的例子进行讲解在链表中删除节点。输入学号,如果学号存在,则在链表中删除,然后打印出当前链表中的节点。如果学号不存在,则给出提示信息。要结束输入时,请输入“-1”,此时打印出链表中的节点信息。

这时上面创建的泛型类就不符合需求了,我们重新创建一个节点类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 演示删除节点使用的节点类
    /// </summary>
    public class StudentNode
    {
        /// <summary>
        /// 学号
        /// </summary>
        public int Number { get; set; }

        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 成绩
        /// </summary>
        public int Score { get; set; }

        /// <summary>
        /// 指针 指向下一个元素
        /// </summary>
        public StudentNode Next { get; set; }

        public StudentNode(int number,string name,int score)
        {
            Number = number;
            Name = name;
            Score = score;
        }
    }
}

链表类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingleLinkedListDemo
{
    public class StudentLinkedList
    {

        public List<StudentNode> ListNode { get; set; }

        public StudentLinkedList()
        {
            ListNode = new List<StudentNode>();
        }

        /// <summary>
        /// 头节点
        /// </summary>
        public StudentNode HeadNode;

        /// <summary>
        /// 尾节点
        /// </summary>
        public StudentNode LastNode;

        /// <summary>
        /// 判断当前链表是否为空链表
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return HeadNode == null;
        }

        /// <summary>
        /// 添加节点
        /// </summary>
        /// <param name="node"></param>
        public void AddNode(StudentNode node)
        {
            StudentNode newNode = node;
            // 判断头节点是否为null,如果为null,那么新建的节点就是头节点,同时也是尾节点
            if (IsEmpty())
            {
                // 如果是空链表,则将头节点和尾节点都指向新建的节点
                HeadNode = newNode;
                LastNode = newNode;
            }
            else
            {
                // 尾节点的指针指向新建的节点
                // 新建的节点变为尾节点
                LastNode.Next = newNode;
                LastNode = newNode;
            }
            // 将新建的节点添加到集合中
            ListNode.Add(newNode);
        }

        /// <summary>
        /// 打印
        /// </summary>
        public void Print()
        {
            StudentNode current = HeadNode;
            while (current != null)
            {
                Console.WriteLine("[" + current.Number + " " + current.Name + " " + current.Score + "]");
                current = current.Next;
            }
            Console.WriteLine();
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="delNode"></param>
        public void DeleteNode(StudentNode delNode)
        {
            StudentNode newNode;
            StudentNode tmpNode;

            // 如果删除的是第一个节点
            if(HeadNode.Number==delNode.Number)
            {
                // 头指针指向第二个节点
                HeadNode = HeadNode.Next;
            }
            else if(LastNode.Number==delNode.Number)
            {
                // 删除的是最后一个节点
                newNode = HeadNode;
                // 循环找到最后一个节点的前一个节点
                // 当退出循环的时候newNode就是最后一个节点的前一个节点
                while(newNode.Next!=LastNode)
                {
                    // 指针后移,指向下一个节点
                    newNode = newNode.Next;
                }
                // 最后一个节点的前一个节点的next赋值为null
                newNode.Next = null;
                LastNode = newNode;
            }
            else
            {
                // 删除的是中间的节点
                newNode = HeadNode;
                tmpNode = HeadNode;
                // 循环找到要删除的节点
                // 循环退出时tmpNode节点就是要删除节点的前一个节点,newNode节点就是要删除的节点
                while(newNode.Number!=delNode.Number)
                {
                    tmpNode = newNode;
                    // 后移,指向下一个节点
                    newNode = newNode.Next;
                }
                // 要删除节点的前一个节点的next指向删除节点的下一个节点
                tmpNode.Next = newNode.Next;
            }
        }

    }
}

Main方法里面调用:

using System;
using System.Collections.Generic;

namespace SingleLinkedListDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 创建一个单向链表
            //int num;
            //string name;
            //int score;

            //Console.WriteLine("请输入5位学生的成绩:");
            //SingleLinkedList<Student> linkedList = new SingleLinkedList<Student>();
            //for (int i = 0; i < 5; i++)
            //{
            //    Console.Write("请输入学号:");
            //    num = int.Parse(Console.ReadLine());
            //    Console.Write("请输入姓名:");
            //    name = Console.ReadLine();
            //    Console.Write("请输入成绩:");
            //    score = int.Parse(Console.ReadLine());
            //    Student student = new Student(number: num, name: name, score: score);
            //    linkedList.AddNode(student);
            //    Console.WriteLine("----------------");
            //}

            //Console.WriteLine();
            //Console.WriteLine("输出学生成绩信息");
            //List<Node<Student>> list = linkedList.ListNode;
            //foreach (var item in list)
            //{
            //    Console.WriteLine($"学号: {item.Data.Number},姓名: {item.Data.Name},成绩: {item.Data.Score}");
            //    Console.WriteLine();
            //}
            #endregion

            #region 删除单向链表中的节点
            Random rand = new Random();
            StudentLinkedList list = new StudentLinkedList();
            int i, j, findword = 0;
            int[,] data = new int[12, 10];
            String[] name = new String[] { "Allen", "Scott",
                "Marry", "Jon", "Mark", "Ricky", "Lisa",
                "Jasica", "Hanson", "Amy", "Bob", "Jack" };
            Console.WriteLine("学号 成绩  学号 成绩  学号 成绩  学号  成绩\n ");
            // 链表里面添加12个节点
            for (i = 0; i < 12; i++)
            {
                data[i, 0] = i + 1;
                data[i, 1] = (Math.Abs(rand.Next(50))) + 50;
                StudentNode node = new StudentNode(data[i, 0], name[i], data[i, 1]);
                list.AddNode(node);
            }
            // 分三行输出
            for (i = 0; i < 3; i++)
            {
                for (j = 0; j < 4; j++)
                    Console.Write("[" + data[j * 3 + i, 0] + "]  [" + data[j * 3 + i, 1] + "]  ");
                Console.WriteLine();
            }
            while (true)
            {
                Console.Write("请输入要删除成绩的学生学号,结束输入-1: ");
                findword = int.Parse(Console.ReadLine());
                if (findword == -1)
                    break;
                else
                {
                    StudentNode current = new StudentNode(list.HeadNode.Number, list.HeadNode.Name, list.HeadNode.Score);
                    current.Next = list.HeadNode.Next;
                    while (current.Number != findword) current = current.Next;
                    list.DeleteNode(current);
                }
                Console.WriteLine("删除后成绩的链表,请注意!要删除的成绩其学生的学号必须在此链表中\n");
                list.Print();
            }
            #endregion

            Console.ReadKey();
        }
    }
}

程序运行结果:

3、单向链表插入新节点

在单向链表中插入新节点,如同一列火车中加入新的车厢,有三种情况:加到第一个节点之前、加到最后一个节点之后以及加到此链表中间任一位置。

1、新节点插入第一个节点之前

将新节点插入到第一个节点之前,新节点即成为此链表的首节点,只需要把新节点的指针指向链表原来的第一个节点,再把链表头指针指向新节点即可,如图所示:

2、新节点插入最后一个节点之后

将新节点插入到最后一个节点之后,只需要把链表的最后一个节点的指针指向新节点,新节点的指针在指向null即可,如图所示:

3、新节点插入链表中间位置

例如插入的节点是在X和Y之间,只需要将X节点的指针指向新节点,如图所示:

然后将新节点的指针指向Y节点即可,如图所示:

下面我们以泛型Node类为例,讲解如何插入节点

using System;
using System.Collections.Generic;

namespace SingleLinkedListDemo
{
    /// <summary>
    /// 单向链表类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class SingleLinkedList<T>
    {
        /// <summary>
        /// 存放所有链表节点的集合
        /// </summary>
        public List<Node<T>> ListNode { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public SingleLinkedList()
        {
            ListNode = new List<Node<T>>();
        }

        /// <summary>
        /// 头节点
        /// </summary>
        private Node<T> HeadNode;

        /// <summary>
        /// 尾节点
        /// </summary>
        private Node<T> LastNode;

        /// <summary>
        /// 判断当前链表是否为空链表
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            return HeadNode == null;
        }

        /// <summary>
        /// 新增节点
        /// </summary>
        public void AddNode(T item)
        {
            // 新建一个节点
            Node<T> newNode = new Node<T>(item);

            // 判断头节点是否为null,如果为null,那么新建的节点就是头节点,同时也是尾节点
            if (IsEmpty())
            {
                // 如果是空链表,则将头节点和尾节点都指向新建的节点
                HeadNode = newNode;
                LastNode = newNode;
            }
            else
            {
                // 尾节点的指针指向新建的节点
                // 新建的节点变为尾节点
                LastNode.Next = newNode;
                LastNode = newNode;
            }
            // 将新建的节点添加到集合中
            ListNode.Add(newNode);
        }

        /// <summary>
        /// 插入节点
        /// </summary>
        /// <param name="item">要插入的节点的值</param>
        /// <param name="index">要插入节点的位置</param>
        public void InsertNode(T item,int index)
        {
            // 创建新的节点
            Node<T> newNode = new Node<T>(item);
            //Node<T> tmpNode = new Node<T>(item);

            // 判断当前链表是否为空链表
            if(IsEmpty())
            {
                HeadNode = newNode;
                LastNode = newNode;
            }
            else
            {
                // 插入第一个节点
                if(index==0)
                {
                    // 新节点执行现在的头节点
                    newNode.Next = HeadNode;
                    // 新节点变为新的头节点
                    HeadNode = newNode;
                }
                else if(index==GetLinkedListLength()-1)
                {
                    // 插入尾节点
                    // 定义一个临时节点tempNode指向HeadNode
                    Node<T> tempNode = HeadNode;
                    // 循环找到尾节点
                    while(true)
                    {
                        // 如果tempNode的next不为null,说明当前节点不是尾节点,则后移
                        if(tempNode.Next!=null)
                        {
                            // 当前tempNode后移
                            tempNode = tempNode.Next;
                        }
                        else
                        {
                            // tempNode的next为null,说明tempNode节点是尾节点,则退出循环
                            break;
                        }
                    }
                    // tempNode是尾节点,则将尾节点的next指向新的节点
                    tempNode.Next = newNode;
                }
                else
                {
                    #region 插入中间位置
                    // 定义临时节点指向头节点
                    Node<T> tempNode = HeadNode;
                    // 经过index-1次循环后移,tempNode移动到要插入位置的前一个节点
                    for (int i = 0; i <=index-1; i++)
                    {
                        // tempNode节点每次后移一个位置
                        tempNode = tempNode.Next;
                    }
                    // 要插入位置的前一个节点
                    Node<T> preNode = tempNode;
                    // 要插入位置的节点
                    Node<T> currentNode = preNode.Next;
                    // 修改next指向,前一个节点指向新节点
                    preNode.Next = newNode;
                    // 新节点指向当前位置的节点
                    newNode.Next = currentNode;
                    #endregion
                }
            }
        }

        /// <summary>
        /// 获取链表长度
        /// </summary>
        /// <returns></returns>
        public int GetLinkedListLength()
        {
            // 长度
            int length = 0;
            if(HeadNode==null)
            {
                length = 0;
            }
            else
            {
                Node<T> tempNode = HeadNode;
                // 循环
                while(true)
                {
                    if(tempNode.Next!=null)
                    {
                        // 当前临时节点后移到下一个节点
                        tempNode = tempNode.Next;
                        // 长度自增
                        length++;
                    }
                    else
                    {
                        // 说明循环到了尾节点,退出循环
                        length++;
                        break;
                    }
                }
            }
            return length;
        }

        /// <summary>
        /// 打印
        /// </summary>
        public void Print()
        {
            //StudentNode current = HeadNode;
            //while (current != null)
            //{
            //    Console.WriteLine("[" + current.Number + " " + current.Name + " " + current.Score + "]");
            //    current = current.Next;
            //}

            Node<T> current = HeadNode;
            while (current != null)
            {
                Console.Write( current.Data+"  ");
                current = current.Next;
            }
            Console.WriteLine();
        }
    }
}

Main方法中调用:

using System;
using System.Collections.Generic;

namespace SingleLinkedListDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 创建一个单向链表
            //int num;
            //string name;
            //int score;

            //Console.WriteLine("请输入5位学生的成绩:");
            //SingleLinkedList<Student> linkedList = new SingleLinkedList<Student>();
            //for (int i = 0; i < 5; i++)
            //{
            //    Console.Write("请输入学号:");
            //    num = int.Parse(Console.ReadLine());
            //    Console.Write("请输入姓名:");
            //    name = Console.ReadLine();
            //    Console.Write("请输入成绩:");
            //    score = int.Parse(Console.ReadLine());
            //    Student student = new Student(number: num, name: name, score: score);
            //    linkedList.AddNode(student);
            //    Console.WriteLine("----------------");
            //}

            //Console.WriteLine();
            //Console.WriteLine("输出学生成绩信息");
            //List<Node<Student>> list = linkedList.ListNode;
            //foreach (var item in list)
            //{
            //    Console.WriteLine($"学号: {item.Data.Number},姓名: {item.Data.Name},成绩: {item.Data.Score}");
            //    Console.WriteLine();
            //}
            #endregion

            #region 删除单向链表中的节点
            //Random rand = new Random();
            //StudentLinkedList list = new StudentLinkedList();
            //int i, j, findword = 0;
            //int[,] data = new int[12, 10];
            //String[] name = new String[] { "Allen", "Scott",
            //    "Marry", "Jon", "Mark", "Ricky", "Lisa",
            //    "Jasica", "Hanson", "Amy", "Bob", "Jack" };
            //Console.WriteLine("学号 成绩  学号 成绩  学号 成绩  学号  成绩");
            //// 链表里面添加12个节点
            //for (i = 0; i < 12; i++)
            //{
            //    data[i, 0] = i + 1;
            //    data[i, 1] = (Math.Abs(rand.Next(50))) + 50;
            //    StudentNode node = new StudentNode(data[i, 0], name[i], data[i, 1]);
            //    list.AddNode(node);
            //}
            //// 分三行输出
            //for (i = 0; i < 3; i++)
            //{
            //    for (j = 0; j < 4; j++)
            //        Console.Write("[" + data[j * 3 + i, 0] + "]  [" + data[j * 3 + i, 1] + "]  ");
            //    Console.WriteLine();
            //}
            //while (true)
            //{
            //    Console.Write("请输入要删除成绩的学生学号,结束输入-1: ");
            //    findword = int.Parse(Console.ReadLine());
            //    if (findword == -1)
            //        break;
            //    else
            //    {
            //        StudentNode current = new StudentNode(list.HeadNode.Number, list.HeadNode.Name, list.HeadNode.Score);
            //        current.Next = list.HeadNode.Next;
            //        while (current.Number != findword) current = current.Next;
            //        list.DeleteNode(current);
            //    }
            //    Console.WriteLine("删除后成绩的链表,请注意!要删除的成绩其学生的学号必须在此链表中\n");
            //    list.Print();
            //}
            #endregion

            #region 单向链表中插入节点
            SingleLinkedList<int> linkedList = new SingleLinkedList<int>();
            linkedList.AddNode(1);
            linkedList.AddNode(45);
            linkedList.AddNode(56);
            linkedList.AddNode(389);
            List<Node<int>> list = linkedList.ListNode;
            Console.WriteLine("插入前链表元素");
            linkedList.Print();
            Console.WriteLine();
            // 插入头节点之前
            linkedList.InsertNode(57, 0);
            Console.WriteLine("插入头节点后链表元素");
            linkedList.Print();
            Console.WriteLine();
            // 插入尾节点之后
            linkedList.InsertNode(123, linkedList.GetLinkedListLength()-1);
            Console.WriteLine("插入尾节点后链表元素");
            linkedList.Print();
            Console.WriteLine();
            // 插入中间节点
            int index= new Random().Next(0, linkedList.GetLinkedListLength() - 1);
            linkedList.InsertNode(935, index);
            Console.WriteLine("插入中间节点后链表元素");
            linkedList.Print();
            Console.WriteLine();
            #endregion
            Console.ReadKey();
        }
    }
}

程序运行结果:

GitHub地址:[email protected]:JiangXiaoLiang1988/SingleLinkedList.git

原文地址:https://www.cnblogs.com/dotnet261010/p/12312376.html

时间: 2024-10-27 16:55:14

链表(二):单向链表的相关文章

数据结构和算法--3链表(单向链表、双向链表、环形单向链表和约瑟夫问题)

链表 链表是以节点的方式来存储 每个节点包含data域和next域,指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定 单向列表 最大特点是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能. 单链表分为两种:有头链表和无头链表. 有头节点的增删改查 定义一个单链表的类: //定义一个SingleLinkedList,单链表,管理HeroNode class SingleLinkedList{ //初始

python数据结构链表之单向链表

本文和大家分享的主要是python中单向链表相关内容,一起来看看吧,希望对大家学习python有所帮助. 单向链表 单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域.这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值. . 表元素域elem用来存放具体的数据. . 链接域next用来存放下一个节点的位置(python中的标识) . 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点. 节点实现 class 

再谈单向链表操作——单向链表的访问与修改

链表的访问 既然理解了链表的构成,对链表的访问也就不成问题了.不过要特别注意的是,对于数组,我们可以利用下标直接访问任何一个元素(这被称为"随机访问"),而对于单向链表,只能从头结点开始,依次进行"顺序访问". 假设我们已经按照前文创建了一个链表,下面我们设计一个函数,查找是否存在某数据: //参数说明:p为头指针,n为所查找的数据 void search_node(l* p, int n) { //若非尾结点,则继续循环 while(p->next != N

线性表的Java实现--链式存储(单向链表)

线性表的Java实现--链式存储(单向链表) 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素.由于不需要按顺序存储,链表在插入.删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢. 使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理.但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空

数据结构-线性表之单向链表--一点一滴

单向链表 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始. 单向链表的数据结构可以分为两部分:数据域和指针域,数据域存储数据,指针域指向下一个储存节点的地址.分为动态单向链表和静态单向链表.单向链表也可以根据是否带头节点分为带头节点结构和无带头节点结构.我们把指向单链表的指针为头指针.头指针所指的不存放数据元素的第一个节点称作头节点.存放数据元素的节点成为第一个数据元素节点. 注:第一个数据元素节点在带头节点单链表中是第二个节点:而在不带头节

Python3中定义一个单向链表

链表是由节点构成的,一个指针代表一个方向,如果一个构成链表的节点都只包含一个指针,那么这个链表就是单向链表. 单向链表中的节点不光有代表方向的指针变量,也有值变量.所以我们定义链表,就是要定义链表中的节点,对链表的操作最后也就是对节点的操作. 这些包含数据的节点们在一种指定的结构下连接起来,成为了一种数据结构——单向链表.以上是我对单向链表的理解. 以下是我用python3对单向链表这种数据结构的一种实现: ''' Python3版单向链表-单向链表简称单链表 单链表中所包含的基本操作: 初始化

自己动手实现java数据结构(二) 链表

1.链表介绍 前面我们已经介绍了向量,向量是基于数组进行数据存储的线性表.今天,要介绍的是线性表的另一种实现方式---链表. 链表和向量都是线性表,从使用者的角度上依然被视为一个线性的列表结构.但是,链表内部存储数据的方式却和向量大不相同:链表的核心是节点.节点存储"数据"的同时还维护着"关联节点的引用".要理解链表,首先必须理解链表的内部节点结构. 最简单的链表结构是单向链表,单向链表中的内部节点存储着数据(data)和其关联的下一个节点的引用(next). da

单链表,双链表,循环链表的区别

单向链表(单链表) 单向链表,它包含两个域,一个信息域和一个指针域.这个链接指向表中的下一个节点,而最后一个节点则 指向一个空值NULL. 单向链表只可向一个方向遍历. 查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置.也可以提前把一个节点的位置另外保存起来,然后直接访问. 双向链表,(双链表) 双向链表中不仅有指向后一个节点的指针,还有指向前一个节点的指针.第一个节点的"前连接"指向NULL,最后一个节点的"后连接"指向NULL. 这

链表(二)——单向链表的基本操作(创建、删除、打印、结点个数统计)

1.指针的联动 通过两个指针分别指向前驱和后继结点,并在单向链表上进行移动,当指针指向待处理的结点时,该结点的前驱也有指针指向. 2.设有一个无序单向链表,且数据域的值均不相同,使指针pmin指向最小值结点,并使指针prem指向最小值结点的前驱结点: 代码片段: for(p = head; p; q = p, p = p->next) { if(pmin->data > p->data) { pmin = p; prem = q; } } 3.单向链表的删除算法 注:使用mallo

数据结构和算法之单向链表二:获取倒数第K个节点

我们在做算法的时候或多或少都会遇到这样的问题,那就是我们需要获取某一个数据集的倒数或者正数第几个数据.那么今天我们来看一下这个问题,怎么去获取倒数第K个节点.我们拿到这个问题的时候自然而然会想到我们让链表从末尾开始next   K-1 次不就是第K-1个节点了么,但是必须要注意一点,这是单向链表.那么这时候的解决思路或许就会出现分歧,大多数人都会想到我们遍历一下链表,获取链表的长度,然后再减去 K 长度的节点,那么我们这个链表的最后一个节点就是原链表的倒数第K个节点:我们看一下实现代码: /**