Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритми та структури даних ЗПІ-91-20210115T104612Z-001 / Лекція 7. Зв_язані списки з подвійним зв_язком.doc
Скачиваний:
28
Добавлен:
15.01.2021
Размер:
160.26 Кб
Скачать

12

Лекція 7. Зв’язані списки з подвійним зв'язком

7.1. Структура списку з подвійним зв’язком

7.2. Операції над списком з подвійним зв’язком

7.3. Реалізація списку з подвійним зв’язком на мові C#

7.1. Структура списку з подвійним зв’язком

Кожен елемент в списку з подвійним зв'язком має покажчик на наступний елемент списку і покажчик на попередній елемент списку. Рис.1 ілюструє характер зв'язків в такому списку. Список, який замість одного має два зв'язки, відрізняється двома основними перевагами.

По-перше, список можна прочитати в обох напрямах. Це не лише спрощує сортування списку, але також дозволяє користувачам бази даних переглядати дані в обох напрямах.

По-друге, і прямий і зворотний зв'язок дозволяють прочитати список повністю і тому при порушенні одного із зв'язків список може бути відновлений по іншому зв'язку. Цю властивість має сенс використовувати при відмовах устаткування, що призводять до порушення списку.

Рис. 1. Список з подвійним зв'язком.

Http://professorweb.Ru/my/csharp/charp_theory/level12/12_8.Php

7.2. Операції над списком з подвійним зв’язком

Для списку з подвійним зв'язком передбачаються три основні операції:

- вставка нового першого елементу;

- вставка нового середнього елементу;

- вставка нового останнього елементу.

Крім цього, для списку з подвійним зв’язком є операції видалення елементу, обхід (переміщення) списку у прямому і зворотному напрямах.

7.3. Реалізація списку з подвійним зв’язком на мові c#

Клас LinkedList<T> реалізує колекцію у вигляді універсального списку з подвійним зв’язком (двозвязного списку). У цьому класі реалізуються інтерфейси ICollection, ICollection<T>, IEnumerable, IEnumerable<T>, ISerializable і IDeserializationCallback.

Таблиця 1. Конструктори клас у LinkedList<T>

Ім’я

Опис

LinkedList<T>()

Створюється порожній зв'язний список

LinkedList<T>(IEnumerable<T>)

Створюється список, що ініціалізується елементами з колекції collection.

Таблиця 2. Властивості класу LinkedList<T>

Ім’я

Опис

Count

Отримує число вузлів, яке насправді зберігається в LinkedList<T>

First

Отримує перший вузол об'єкту LinkedList<T>.

Last

Отримує останній вузол об'єкту LinkedList<T>.

Як і в більшості інших реалізацій зв'язних списків, в класі LinkedList<T> містяться значення, що зберігаються у вузлах списку, де знаходяться також посилання на попередні і наступні елементи списку. Ці вузли є об'єктами класу LinkedListNode<T>.

У класі LinkedListNode<T> реалізуються чотири наступні властивості.

Таблиця 3 Властивості класу LinkedListNode<T>.

Ім’я

Опис

Next

Посилання на наступний вузол списку або null (якщо вузол відсутній)

Previous

Посилання на попередній вузол списку або null (якщо вузол відсутній)

List

Отримання посилання на сам список

Value

Встановлення чи отримання значення, що знаходиться у вузлі списку

За допомогою властивостей Next і Previous виконують посилання на попередній і наступний вузли списку відповідно, що дає можливість обходити список в обох напрямах.

Таблиця 4. Основні методи класу LinkedList<T>.

Ім'я

Опис

AddAfter(LinkedListNode<T>, LinkedListNode<T>)

Додає заданий новий вузол після заданого існуючого вузла в LinkedList<T>.

AddAfter(LinkedListNode<T>, T)

Додає новий вузол, що містить задане значення, після заданого існуючого вузла в LinkedList<T>.

AddBefore(LinkedListNode<T>, LinkedListNode<T>)

Додає заданий новий вузол перед заданим існуючим вузлом в LinkedList<T>.

AddBefore(LinkedListNode<T>, T)

Додає новий вузол, що містить задане значення, перед заданим існуючим вузлом в LinkedList<T>.

AddFirst(T)

Додає новий вузол, що містить задане значення, в початок LinkedList<T>.

AddFirst(LinkedListNode<T>)

Додає заданий новий вузол в початок LinkedList<T>.

AddLast(T)

Додає новий вузол, що містить задане значення, в кінець LinkedList<T>.

AddLast(LinkedListNode<T>)

Додає заданий новий вузол в кінець об'єкту LinkedList<T>.

Clear

Видаляє усі вузли з LinkedList<T>.

Contains

Визначає, чи належить значення об'єкту LinkedList<T>.

CopyTo

Копіює цілий масив LinkedList<T> у сумісний одновимірний масив Array, починаючи із заданого індексу цільового масиву.

Equals(Object)

Визначає, чи рівний заданий об'єкт поточному об'єкту. (Успадковано від Object.)

Finalize

Дозволяє об'єкту спробувати звільнити ресурси і виконати інші операції очищення, перш ніж об'єкт буде знищено в процесі збирання сміття. (Успадковано від Object.)

Find

Знаходить перший вузол, що містить вказане значення.

FindLast

Знаходить останній вузол, що містить вказане значення.

GetEnumerator

Повертає нумератор, що здійснює перебір елементів LinkedList<T>.

GetHashCode

Грає роль хеш-функції для певного типу. (Успадковано від Object.)

GetType

Повертає об'єкт Type для поточного екземпляра. (Успадковано від Object.)

Remove(T)

Видаляє перше входження заданого значення з LinkedList<T>

Remove(LinkedListNode<T>)

Видаляє заданий вузол з об'єкту LinkedList<T>.

RemoveFirst

Видаляє вузол на початку LinkedList<T>.

RemoveLast

Видаляє вузол у кінці LinkedList<T>.

ToString

Повертає рядок, що представляє поточний об'єкт. (Успадковано від Object.)

Приклад 1 . Демонструє роботу з LinkedList<T>

https://msdn.microsoft.com/ru-ru/library/he2s3bh7(v=vs.110).aspx

using System;

using System.Text;

using System.Collections.Generic;

public class Example

{

public static void Main()

{

// Create the link list.

string[] words =

{ "the", "fox", "jumped", "over", "the", "dog" };

LinkedList<string> sentence = new LinkedList<string>(words);

Display(sentence, "The linked list values:");

Console.WriteLine("sentence.Contains(\"jumped\") = {0}",

sentence.Contains("jumped"));

// Add the word 'today' to the beginning of the linked list.

sentence.AddFirst("today");

Display(sentence, "Test 1: Add 'today' to beginning of the list:");

// Move the first node to be the last node.

LinkedListNode<string> mark1 = sentence.First;

sentence.RemoveFirst();

sentence.AddLast(mark1);

Display(sentence, "Test 2: Move first node to be last node:");

// Change the last node be 'yesterday'.

sentence.RemoveLast();

sentence.AddLast("yesterday");

Display(sentence, "Test 3: Change the last node to 'yesterday':");

// Move the last node to be the first node.

mark1 = sentence.Last;

sentence.RemoveLast();

sentence.AddFirst(mark1);

Display(sentence, "Test 4: Move last node to be first node:");

// Indicate, by using parentheisis, the last occurence of 'the'.

sentence.RemoveFirst();

LinkedListNode<string> current = sentence.FindLast("the");

IndicateNode(current, "Test 5: Indicate last occurence of 'the':");

// Add 'lazy' and 'old' after 'the' (the LinkedListNode named current).

sentence.AddAfter(current, "old");

sentence.AddAfter(current, "lazy");

IndicateNode(current, "Test 6: Add 'lazy' and 'old' after 'the':");

// Indicate 'fox' node.

current = sentence.Find("fox");

IndicateNode(current, "Test 7: Indicate the 'fox' node:");

// Add 'quick' and 'brown' before 'fox':

sentence.AddBefore(current, "quick");

sentence.AddBefore(current, "brown");

IndicateNode(current, "Test 8: Add 'quick' and 'brown' before 'fox':");

// Keep a reference to the current node, 'fox',

// and to the previous node in the list. Indicate the 'dog' node.

mark1 = current;

LinkedListNode<string> mark2 = current.Previous;

current = sentence.Find("dog");

IndicateNode(current, "Test 9: Indicate the 'dog' node:");

// The AddBefore method throws an InvalidOperationException

// if you try to add a node that already belongs to a list.

Console.WriteLine("Test 10: Throw exception by adding node (fox) already in the list:");

try

{

sentence.AddBefore(current, mark1);

}

catch (InvalidOperationException ex)

{

Console.WriteLine("Exception message: {0}", ex.Message);

}

Console.WriteLine();

// Remove the node referred to by mark1, and then add it

// before the node referred to by current.

// Indicate the node referred to by current.

sentence.Remove(mark1);

sentence.AddBefore(current, mark1);

IndicateNode(current, "Test 11: Move a referenced node (fox) before the current node (dog):");

// Remove the node referred to by current.

sentence.Remove(current);

IndicateNode(current, "Test 12: Remove current node (dog) and attempt to indicate it:");

// Add the node after the node referred to by mark2.

sentence.AddAfter(mark2, current);

IndicateNode(current, "Test 13: Add node removed in test 11 after a referenced node (brown):");

// The Remove method finds and removes the

// first node that that has the specified value.

sentence.Remove("old");

Display(sentence, "Test 14: Remove node that has the value 'old':");

// When the linked list is cast to ICollection(Of String),

// the Add method adds a node to the end of the list.

sentence.RemoveLast();

ICollection<string> icoll = sentence;

icoll.Add("rhinoceros");

Display(sentence, "Test 15: Remove last node, cast to ICollection, and add 'rhinoceros':");

Console.WriteLine("Test 16: Copy the list to an array:");

// Create an array with the same number of

// elements as the inked list.

string[] sArray = new string[sentence.Count];

sentence.CopyTo(sArray, 0);

foreach (string s in sArray)

{

Console.WriteLine(s);

}

// Release all the nodes.

sentence.Clear();

Console.WriteLine();

Console.WriteLine("Test 17: Clear linked list. Contains 'jumped' = {0}",

sentence.Contains("jumped"));

Console.ReadLine();

}

private static void Display(LinkedList<string> words, string test)

{

Console.WriteLine(test);

foreach (string word in words)

{

Console.Write(word + " ");

}

Console.WriteLine();

Console.WriteLine();

}

private static void IndicateNode(LinkedListNode<string> node, string test)

{

Console.WriteLine(test);

if (node.List == null)

{

Console.WriteLine("Node '{0}' is not in the list.\n",

node.Value);

return;

}

StringBuilder result = new StringBuilder("(" + node.Value + ")");

LinkedListNode<string> nodeP = node.Previous;

while (nodeP != null)

{

result.Insert(0, nodeP.Value + " ");

nodeP = nodeP.Previous;

}

node = node.Next;

while (node != null)

{

result.Append(" " + node.Value);

node = node.Next;

}

Console.WriteLine(result);

Console.WriteLine();

}

}

Приклад 2. У прикладі створюється список Прізвищ та виконується перегляд списку у прямому і зворотному напрямах.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Lab_7

{

class Program

{

static void Main(string[] args)

{

// Створимо зв'язний список

LinkedList<string> link = new LinkedList<string>();

//Додамо декілька елементів

link.AddFirst("Іванов");

link.AddFirst("Петров");

link.AddFirst("Сидоров");

link.AddFirst("Коваленко");

// Відобразимо елементи в прямому напрямі

LinkedListNode<string> node;

Console.WriteLine("Елементи списку у прямому напрямку: ");

for (node = link.First; node != null; node = node.Next)

Console.Write(node.Value + "\t");

// Відобразимо елементи у зворотному напрямі

Console.WriteLine("\n\nЕлементи списку у зворотньому напрямку: ");

for (node = link.Last; node != null; node = node.Previous)

Console.Write(node.Value + "\t");

Console.ReadKey();

}

}

}

Приклад 3. Форма для роботи зі списком

У прикладі створюється клас Student і зв’язаний список об’єктів класу. Керування роботою зі списком виконується за допомогою Windows Forms. Програма дозволяє проглядати вузли списку у прямому і зворотному напрямах, додавати, змінювати та видаляти вузли списку.

файл Student.cs – код класу

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace WinForm_1

{

class Student

{

//Властивості

public string FistName { get; set; } //ім'я

public string LastName{ get; set; } //прізвище

public string Role { get; set; } // роль

public int Course { get; private set; }

public int Rating { get; set; }

public Student(string f, string n, int cource, int rating)

{

//конструктор з параметрами

//конструктор з параметрами. Ініціалізація полів і властивостей

LastName = f;

FistName = n;

Course = cource;

Rating = rating;

}

public Student()

{ }

public string GetRole(int course)

{

if (course <= 4)

Role = "бакалавр";

else

Role = "магістр";

return Role;

}

public void St_Rating(int student_rating)

{

if (student_rating >= 82)

Console.WriteLine("Привіт відмінникам");

else

if (student_rating <= 45)

Console.WriteLine("Перездача! Треба краще вчитися!");

else

Console.WriteLine("Можна вчитися ще краще!");

}

}

}

Форма

Код форми

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

namespace WinForm_18

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

LinkedList<Student> list_Student = new LinkedList<Student>(); //список

LinkedListNode<Student> node; // вузол списку

private void Form1_Load(object sender, EventArgs e)

{

//початок роботи форми

CreateListStudent();

}

public void CreateListStudent()

{

//значення поточного вузла виводимо у поля форми

list_Student.AddFirst(new Student("Батиренко", "Артем", 4, 90));

list_Student.AddFirst(new Student("Сахно", "Name",4,85));

list_Student.AddFirst(new Student("Сусла", "Name2",4,56));

list_Student.AddFirst(new Student("Ярославський","Name",4,56));

node = list_Student.First;

SetNode();

}

private void SetNode()

{ //виведення на форму першого елемента списку

txtLatName.Text = node.Value.LastName;

txtFirsName.Text = node.Value.FistName;

txtCource.Text = node.Value.Course.ToString();

txtRating.Text = node.Value.Rating.ToString();

}

private void btmRole_Click(object sender, EventArgs e)

{

Student st = new Student();

int course = int.Parse(txtCource.Text);

txtRole.Text = st.GetRole(course);

}

private void btnFirst_Click(object sender, EventArgs e)

{

//First

node = list_Student.First;

SetNode();

}

private void btnLast_Click(object sender, EventArgs e)

{

//Last

node = list_Student.Last;

SetNode();

}

private void btnPrev_Click(object sender, EventArgs e)

{

//Prew

if (node != list_Student.First)

{

node = node.Previous;

SetNode();

}

else { //початок списку

node = list_Student.First;

SetNode();

}

}

private void btnNext_Click(object sender, EventArgs e)

{

if (node != list_Student.Last)

{

node = node.Next;

SetNode();

}

else

{ //кінець списку

node = list_Student.Last;

SetNode();

}

}

private void btnAdd_Click(object sender, EventArgs e)

{

//ADD to List - Clear textBoxs

ClearForm();

}

private void ClearForm()

{

txtLatName.Text = "";

txtFirsName.Text ="";

txtCource.Text = "";

txtRating.Text = "";

txtRole.Text = "";

}

private void btnSave_Click(object sender, EventArgs e)

{

// Add to List

list_Student.AddFirst(new Student(txtLatName.Text, txtFirsName.Text, int.Parse(txtCource.Text), int.Parse(txtRating.Text)));

}

private void btnClear_Click(object sender, EventArgs e)

{

ClearForm();

}

private void btnDel_Click(object sender, EventArgs e)

{

//Delete from List

list_Student.Remove(node);

ClearForm();

}

private void button1_Click(object sender, EventArgs e)

{

this.Close();

}

}

}

Контрольні запитання і завдання для самостійної роботи

1. Поясніть структуру списку з подвійним зв’язком.

2. Які операції потрібно реалізувати над списком з подвійним зв’язком?

3. Яка перевага використання списку з подвійним зв’язком перед звичайним лінійним списком?

4. Який клас мови С# реалізує список з подвійним зв’язком?

5. Чи можна вставити елемент у середину списку з подвійним зв’язком? Чи збережеться при цьому порядок елементів?

6. Чи можна видаляти елементи із середини списку?

7. Як створити порожній список з подвійним зв’язком на мові C#?

8. Як створити список подвійним зв’язком для роботи з об’єктами класу Person на мові C#?

9. Як отримати значення, що знаходиться у вузлі списку LinkedListNode?

10. Яке призначення класу LinkedListNode<T>?

11. Як додати на мові C# новий вузол у початок списку LinkedList?

12. Реалізувати на мові C# роботу зі списком з подвійним зв’язком для запису адрес