2008-10-29 4 views
4

Привет, я пытаюсь получить некоторую практику со связанными списками.Есть ли у меня код связанного списка?

Я определил класс объектов под названием 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; 
     } 
} 

, а затем Node класс:

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; 
     } 
} 

и LinkedList:

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) 
} 

Мне нужно организовать эти данные с помощью «тип структуры данных связанных списков».

Содержит все методы связанного списка как Добавление узлов в список, как я узнал -> (Вставка), Удаление узлов из списка, как я узнал -> ((Удалить), Перемещение списков I 've learn -> ((PrintList), поиск узла в списке, который я узнал, -> ((Найти, FindPrevious) проблему, которую я самоучиваюсь, и я попытался выполнить поиск в сети и прочитать больше из глупый C#, который был катастрофой. Я сделал слишком много, что мне так грустно, что я не знаю, как это сделать.

Я стараюсь использовать эти классы для написания исполняемой программы и проверить его.

Если вы не хотите помогать в заполнении этой программы (надеюсь, что нет t) по крайней мере, покажу мне некоторые настоящие примеры или идеи, ведь я самоуверенный разработчик :-)

+0

«Связанный массив списков» для меня не имеет смысла. Это либо связанный список, либо массив (то, что вы описываете, является связанным списком). Я ничего не знаю об этом. – Herms 2008-10-29 19:42:19

+1

Я попытался отредактировать вопрос, чтобы сделать немного больше смысла, но абзац в нижней части (начиная с «Содержать все») просто слишком запутан. – swilliams 2008-10-29 19:52:42

ответ

14
 
the head of the list. 
(item1 
    Element: student1 
    Next ------------> (item2 
)      Element: student2 
         Next ------------> (item3 
        )      Element: student3 
              Next: null 
              ) 
              the tail of the list. 

Прежде всего, для вас, чтобы иметь возможность написать класс StudentList, вам нужно написать код клиента первым. Клиентский код - это код, который использует ваш список учеников. Кроме того, не просто напишите одну вещь за раз и выбросьте ее. Вместо этого напишите целую кучу [тестовых] случаев, в которых вам необходимо взаимодействовать с StudentList. Пишите также исключительные случаи. Но не стоит соблазнять писать швейцарский армейский нож класса, который делает все только потому, что может. Напишите минимальный объем кода, который выполняет задание.

Как вам нужно использовать класс, будет сильно диктовать, как будет построен класс. В этом суть TDD или Test Driven Design.

Ваша самая большая проблема, которую я вижу, - вы не представляете, как вы хотите использовать класс. Поэтому давайте сделаем это в первую очередь.

// create a list of students and print them back out. 
StudentList list = new StudentList(); 
list.Add(new Student("Bob", 1234, 2, 'A')); 
list.Add(new Student("Mary", 2345, 4, 'C')); 

foreach(Student student in list) 
{ 
    Console.WriteLine(student.Name); 
} 

Я добавляю учащихся в список, а затем распечатываю их.

Мне не нужно, чтобы мой клиентский код отображался внутри 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 никогда не показывает, как этот список реализован. Скрытие реализации - важная концепция ОО.

Если мы действительно разрешили клиентскому коду напрямую манипулировать списком, не было бы места, поскольку 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; 
} 

Операция Add должна найти последний элемент в списке, а затем положить новый ListNode в конец. Не ужасно эффективно. В настоящее время O (N), и добавление будет замедляться по мере увеличения списка.

Немного оптимизирован для вставок и перезаписи метода 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, нам нужно предоставить компилятору перечислитель для использования, даже если код, который мы пишем, явно не использует перечислитель.

Во-первых, давайте снова рассмотрим, как мы перебираем связанный список.

// don't add this to StudentList 
void IterateOverList(ListNode current) 
{ 
    while (current != null) 
    { 
     current = current.Next; 
    } 
} 

Хорошо. поэтому перейдем к циклу foreach C# и вернем перечислитель. Для этого мы меняем StudentList для реализации IEnumerable. Это немного продвинулось, но вы должны понять, что происходит.

// 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 
} 

Здесь вы можете увидеть итерацию связанного списка. Не добавляйте ключевое слово yield. Вся доходность возвращает текущий ученик обратно в цикл foreach. Перечислитель прекращает возвращать учеников, когда он добирается до конца связанного списка.

И все! Код работает так, как мы этого хотим.


* Это далеко не единственный способ реализовать список.Я решил разместить логику списка в StudentList и сохранить ListNode очень простой. Но код делает только то, что мне нужно для моего самого первого модульного теста, и не более того. Вы можете сделать больше оптимизаций, и есть другие способы построения списка.

Перейти к началу страницы Что вам нужно сделать, это сначала создать [unit] тесты для выполнения кода, а затем добавить требуемую реализацию.


* fyi Я также переписал класс Студента. Плохое имя и странный корпус от C# persepctive, не говоря уже о том, что код, который вы предоставили, не компилируется. Я предпочитаю _ в качестве лидера для частных переменных-членов. Некоторым людям это не нравится, но вы новичок в этом, поэтому я оставлю их, потому что их легко заметить.

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; } } 
} 
  • проверки параметров
  • обратить внимание на другую обшивке свойств, классов и переменных.
  • скрыть конструктор по умолчанию. Почему я хочу создавать студентов без реальных данных?
  • предоставляют некоторые свойства только для чтения.
    • Этот класс является неизменным, как указано (т. Е. Как только вы создаете ученика, вы не можете его изменить).
1

На самом деле, я не вижу причины писать собственный список связанных в C# (иначе, чем узнать, как это работает), так как .NET уже содержит общий класс LinkedList.

+0

Для домашней работы CS. – Tim 2008-10-29 19:17:20

+0

Вы правы, но я хочу попробовать, я даже сейчас пытаюсь создать свой собственный математический класс вместо bulit в математическом классе, который включает GCD и LCM. Мне очень нравится это делать (я назову его MyMath :-)). Так вы можете помочь – 2008-10-29 19:18:09

+0

ждать, вы изучаете CS и используете C#? – 2008-10-29 19:18:21

0

Ваш вопрос, как я его читаю, слишком расплывчатый. Я бы начал с «связанных списков» в googling или собрал книгу о «структурах данных». Когда вы сталкиваетесь с конкретной проблемой, спросите ее здесь, и я уверен, что кто-то вам поможет.

+0

хорошо, у меня проблема, и я сделал большую часть, и мне очень больно использовать Google, я нашел тысячи артикулов, и каждый из них отличается от другого, если вы знаете пример где-то это similer к этому, пожалуйста, напишите. – 2008-10-29 19:26:39

2

Я сделаю это для вас! Вам нужно нарисовать диаграммы с каждым узлом в виде окна и выяснить, какой код вам нужно использовать для изменения списка для каждой операции. Смотрите это какое-то вдохновение:

http://en.wikipedia.org/wiki/Linked_list

Диаграмма там не показывает основной класса списка, как ящик, который вы должны иметь, с двумя стрелами, выходящими из него для заголовка и хвоста.

Нарисуйте несколько диаграмм для двух случаев в методе Insert, чтобы понять, что происходит. Одна диаграмма, когда в списке нет ничего, а заголовок - null, а другая диаграмма, если в списке есть что-то еще. Затем оттуда выполняются другие операции.

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; 
     } 
    } 
} 
2

Операции, которые отсутствуют являются:

Добавить:

установить связь хвостового узла быть добавленный узел и установите хвост, чтобы быть новый узел.

Удалить/Удалить:

немного сложнее, если вы не имеете дважды связанный список, но с односвязным списком идет Повсеместно он список из головы, пока не найдете нужный узел требует Сохраняя предыдущий узел в отдельной переменной. Когда вы обнаружите удаляемый узел, установите ссылку «Связь предыдущего узла» на эту ссылку. Оптимизация может состоять в том, чтобы проверить, что это не ссылка, которую вы ищете. В качестве альтернативы можно сделать двойной список, и вам не нужно отслеживать предыдущий узел.

Поиск:

Traverse список от узла к узлу, пока вы не найдете тот, который вы ищете.

читать эту wikipedia article for more info.

2

Посмотрите на this...

Хотя, если вы действительно хотите, чтобы узнать, как сделать это, вы должны записать его в С или С ++, по крайней мере, то вы бы делать что-то полезное ...

1

Концепция связанных списков не очень сложно понять. Реализация с другой стороны ... может немного запутаться.

Я также могу понять ваше разочарование в попытке найти информацию в Интернете об этом. Я был в вашей лодке раньше, и все меняется от сайта к сайту. Вы действительно можете захотеть инвестировать в книгу структур данных, поскольку, по вашему мнению, информация, которую вы найдете, будет намного более понятной и полезной, чем большая часть информации, которую вы найдете в дикой природе.

Реализация связанного списка в Java/C# будет намного проще, если вы раньше не использовали ll. Однако, как только вы почувствуете себя лучше, вы получите гораздо лучшее понимание для ll, создав их на C/C++.

Из вашего кода выше вам будет лучше думать о каждом S_Node как о простом узле, который содержит объект Student, вместо того, чтобы думать о нем как о узле Стьюдента (надеемся, что это имеет смысл). Те же правила применяются к вашему классу S_LinkedList. Связанный список - это режим списка узлов. Эти узлы содержат объекты Student.

Надеюсь, что это поможет.

1

Попробуйте это как ваш класс учеников.

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; 
    } 
} 
Смежные вопросы