C# 这个链表代码我用完了吗?

C# 这个链表代码我用完了吗?,c#,linked-list,C#,Linked List,嗨,我想练习一下链表 我定义了一个名为Student的对象类: public class Student { protected string Student_Name; protected int Student_ID; protected int Student_Mark; protected char Student_Grade; public Student() // default Constructor

嗨,我想练习一下链表

我定义了一个名为
Student
的对象类:

public class Student
{
      protected string  Student_Name;
      protected int Student_ID;
      protected int Student_Mark;
      protected char    Student_Grade;

      public Student()  // default Constructor
      {
         Student_Name = "           ";
         Student_ID = 0;
         Student_Mark = 0;
         Student_Grade = ' ';
        }

      public Student(string Sname, int Sid, int Smark, char Sgrade) // Constructor
      {
         int len = sname.Length;
         Student_Name = sname.Substring(0, len);
         //Student_Name = sname.Substring(0, sname.Length);
         Student_ID = Sid;
         Student_Mark = Smark;
         Student_Grade = Sgrade;
      }
}
然后是
节点
类:

public class S_Node
{
      public Student    Element;
      public S_Node Link;

      public S_Node()
      {
         Element = new Student();
         Link = null;
      }

      public Node(Student theElement)
      {
         Element = theElement;
         Link = null;
      }
}
以及
链接列表

public class S_LinkedList
{
    protected S_Node header;
    protected S_Node tail;

    public S_LinkedList()
    {
       header = new S_Node();
       Tail = new S_Node();
       header.Link = Tail;
    }

    // METHODS which i don't know how to do it (never use linkedlist before)
}
我需要使用“linkedlist数据结构类型”组织此数据

包含linkedlist的所有方法,如向列表中添加节点(如我所了解的)-->(插入)、从列表中删除节点(如我所了解的)-->((删除)、遍历列表(如我所了解的)-->((打印列表)、在列表中查找节点(如我所了解的)-->((查找,FindPrevious)问题是我在自学,我试着搜索网络,从愚蠢的C#那里读更多的东西,那是一场灾难。 我做的太多了,我太伤心了,我不知道如何完成它

我正在努力使用这些类来编写可执行程序并对其进行测试


如果你不想帮助完成这个项目(希望不是),至少给我看一些真实的例子或想法,毕竟我是一个自学成才的极客:-)

事实上,我不认为有理由用C#写你自己的链表(除了学习它的工作原理)因为.NET已经包含LinkedList泛型类。

我读到你的问题时,你的问题太模糊了。我会先在谷歌上搜索“链接列表”或拿起一本关于“数据结构”的书。当你遇到一个特定的问题时,在这里问一下,我相信有人会帮助你。

我会为你做一个问题!你需要用每个问题绘制图表将de设置为一个框,并计算出您需要使用哪些代码来更改每个操作的列表。请参阅以下内容以获得一些启示:

那里的图表没有将主列表类显示为一个框,您应该有一个框,其中有两个箭头指向头部和尾部

在Insert方法中为这两种情况绘制一些图表,以了解发生了什么。一个图表表示列表中没有任何内容且标题为空,另一个图表表示列表中已有内容。然后从中计算出其他操作

public class S_LinkedList {

    protected S_Node header = null;

    protected S_Node tail = null;

    public S_LinkedList()
    {
    }

    // METHODS which i don't know how to do it (never use linkedlist before)
    void Insert(Student s)
    {
        if( header == null )
        {
            header = new S_Node(s);
            tail = header;
        }
        else
        {
            tail.Link = new S_Node(s);
            tail = tail.Link;
        }
    }
}

您缺少的操作包括:

添加:

将尾部节点的链接设置为添加的节点,并将尾部设置为新节点

删除/删除:

如果您没有双链接列表,但使用单链接列表,则需要从列表的开头遍历列表,直到找到需要将前一个节点保留在单独变量中的节点。当您找到要删除的节点时,请将前一个节点的链接设置为该节点链接。优化方法可能是检查该节点是否存在链接你正在寻找的链接。 或者,将其设置为双链接列表,您不需要跟踪上一个节点

查找:

从一个节点到另一个节点遍历列表,直到找到要查找的节点

读这篇

看看


虽然你真的想学习如何做这件事,但是你应该用C或C++写,至少你会做一些有用的事情……< /P> < P>链接列表的概念并不难理解。另一方面,实现可能会有点棘手。 我也能理解你在网上寻找相关信息时的挫败感。我以前也在你的船上,每个站点的情况都不尽相同。你可能真的想投资一本数据结构书,因为我认为你找到的信息比你在野外找到的大多数信息都要清晰和有用得多

如果您以前从未使用过ll,那么在Java/C#中实现链表会容易得多。但是,一旦您对它有了更好的了解,您将通过在C/C++中创建ll来更好地理解它

从上面的代码中,您最好将每个S_节点视为包含Student对象的常规节点,而不是将其视为Student节点(希望有意义)。同样的规则适用于S_LinkedList类。链表是由节点组成的列表模式。这些节点包含Student对象


希望这对你有所帮助。

试着把它作为你的学生课堂。

public class Student
{
    protected string Name;
    protected int ID;
    protected int Mark;
    protected char Grade;

    public Student()  // default Constructor
    {
        Name = "";
        ID = 0;
        Mark = 0;
        Grade = '';
    }

    public Student(string Name, int ID, int Mark, char Grade) // Constructor
    {
        this.Name = Name;
        this.ID = ID;
        this.Mark = Mark;
        this.Grade = Grade;
    }
}
我将学生添加到列表中,然后打印出来

我不需要客户端代码在StudentList中查看。因此StudentList隐藏了它如何实现链接列表。让我们来编写StudentList的基础知识

public class StudentList 
{
    private ListNode _firstElement; // always need to keep track of the head.

    private class ListNode
    {
        public Student Element { get; set; }
        public ListNode Next { get; set; }
    }

    public void Add(Student student) { /* TODO */ }

}
StudentList非常基本。它在内部跟踪第一个节点或头节点。显然,始终需要跟踪第一个节点

您可能还想知道为什么ListNode是在StudentList内部声明的。发生的情况是ListNode类只能由StudentList类访问。之所以这样做,是因为StudentList不想向其内部实现提供详细信息,因为它控制对列表的所有访问。StudentList从不显示列表是如何访问的实现隐藏是一个重要的OO概念

如果我们允许客户端代码直接操作列表,那么将StudentList放在首位就没有意义了

让我们继续执行Add()操作

public void Add(Student student)
{
    if (student == null)
        throw new ArgumentNullException("student");

    // create the new element
    ListNode insert = new ListNode() { Element = student };

    if( _firstElement == null )
    {
        _firstElement = insert;
        return;
    }

    ListNode current = _firstElement;
    while (current.Next != null)
    {
        current = current.Next;
    }

    current.Next = insert;
}
添加操作必须找到列表中的最后一项,然后将新的ListNode放在末尾。但效率不高。当前为O(N),随着列表变长,添加速度会变慢

让我们对插入进行一些优化,并重写Add方法。为了加快Add速度,我们需要做的就是让StudentList跟踪列表中的最后一个元素

private ListNode _lastElement;  // keep track of the last element: Adding is O(1) instead of O(n)

public void Add(Student student)
{
    if( student == null )
        throw new ArgumentNullException("student");

    // create the new element
    ListNode insert = new ListNode() { Element = student };

    if (_firstElement == null)
    {
        _firstElement = insert;
        _lastElement = insert;
        return;
    }

    // fix up Next reference
    ListNode last = _lastElement;
    last.Next = insert;
    _lastElement = insert;
}
现在,当我们添加时,我们不需要迭代。我们只需要跟踪头部和尾部引用

下一步:foreach循环。StudentList是一个集合,作为一个集合,我们要在它上面枚举并使用C#的
foreach
。C#编译器不能神奇地迭代。为了使用foreach循环,我们需要为编译器提供一个枚举器来使用,即使我们编写的代码没有显式地使用枚举器或者

首先,让我们
public void Add(Student student)
{
    if (student == null)
        throw new ArgumentNullException("student");

    // create the new element
    ListNode insert = new ListNode() { Element = student };

    if( _firstElement == null )
    {
        _firstElement = insert;
        return;
    }

    ListNode current = _firstElement;
    while (current.Next != null)
    {
        current = current.Next;
    }

    current.Next = insert;
}
private ListNode _lastElement;  // keep track of the last element: Adding is O(1) instead of O(n)

public void Add(Student student)
{
    if( student == null )
        throw new ArgumentNullException("student");

    // create the new element
    ListNode insert = new ListNode() { Element = student };

    if (_firstElement == null)
    {
        _firstElement = insert;
        _lastElement = insert;
        return;
    }

    // fix up Next reference
    ListNode last = _lastElement;
    last.Next = insert;
    _lastElement = insert;
}
// don't add this to StudentList
void IterateOverList( ListNode current )
{
    while (current != null)
    {
        current = current.Next;
    }
}
// StudentList now implements IEnumerable<Student>
public class StudentList : IEnumerable<Student>
{
    // previous code omitted

    #region IEnumerable<Student> Members
    public IEnumerator<Student> GetEnumerator()
    {
        ListNode current = _firstElement;

        while (current != null)
        {
            yield return current.Element;
            current = current.Next;
        }
    }
    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    #endregion
}
public class Student
{
    private string _name;
    private int _id;
    private int _mark;
    private char _letterGrade;

    private Student()  // hide default Constructor
    { }

    public Student(string name, int id, int mark, char letterGrade) // Constructor
    {
        if( string.IsNullOrEmpty(name) )
            throw new ArgumentNullException("name");
        if( id <= 0 )
            throw new ArgumentOutOfRangeException("id");

        _name = name;
        _id = id;
        _mark = mark;
        _letterGrade = letterGrade;
    }
    // read-only properties - compressed to 1 line for SO answer.
    public string Name { get { return _name; } }
    public int Id { get { return _id; } }
    public int Mark { get { return _mark; } }
    public char LetterGrade { get { return _letterGrade; } }
}