445 lines
13 KiB
Markdown
445 lines
13 KiB
Markdown
---
|
||
title: Data Structure Linked List
|
||
localeTitle: Связанный список данных
|
||
---
|
||
Подобно тому, как гирлянда сделана с цветами, связанный список состоит из узлов. Каждый цветок на этой гирлянде мы называем узлом. И каждый из узлов указывает на следующий узел в этом списке, а также имеет данные (здесь это тип цветка).
|
||
|
||
## Типы
|
||
|
||
1. Одиночный список
|
||
|
||
Одиночные списки содержат узлы, у которых есть поле `data` а также `next` поле, которое указывает на следующий узел в последовательности. Операциями, которые могут выполняться в одиночных списках, являются вставка, удаление и обход.
|
||
|
||
\`
|
||
```
|
||
Singly Link List
|
||
```
|
||
|
||
* * *
|
||
```
|
||
head
|
||
|
|
||
|
|
||
+-----+--+ +-----+--+ +-----+------+
|
||
| 1 |o-----> | 2 |o-----> | 3 | NULL |
|
||
+-----+--+ +-----+--+ +-----+------+
|
||
```
|
||
|
||
\`
|
||
|
||
заявка
|
||
|
||
Внутренняя реализация CPython, фреймы и оцениваемые переменные хранятся в стеке.
|
||
|
||
Для этого нам нужно итерации только вперед aur получить голову, поэтому используется одиночный связанный список.
|
||
|
||
1. Дважды связанный список
|
||
|
||
Дважды связанные списки содержат узел, у которого есть поле `data` , `next` поле и другое поле ссылки `prev` указывающее на предыдущий узел в последовательности.
|
||
|
||
\`
|
||
|
||
Дважды связанный список
|
||
|
||
* * *
|
||
```
|
||
head
|
||
|
|
||
|
|
||
+------+-----+--+ +--+-----+--+ +-----+------+
|
||
| | |o------> | |o------> | | |
|
||
| NULL | 1 | | 2 | | 3 | NULL |
|
||
| | | <------o| | <------o| | |
|
||
+------+-----+--+ +--+-----+--+ +-----+------+
|
||
```
|
||
|
||
\`
|
||
|
||
заявка
|
||
|
||
Кэш браузера, который позволяет вам нажать кнопку BACK и FORWARD. Здесь нам нужно поддерживать двусвязный список с `URLs` качестве поля данных, чтобы разрешить доступ в обоих направлениях. Чтобы перейти к предыдущему URL-адресу, мы будем использовать поле `prev` и для перехода к следующей странице мы будем использовать `next` поле.
|
||
|
||
1. Циркулярный список ссылок
|
||
|
||
Циклические связанные списки - это односвязный список, в котором последний узел, `next` поле указывает на первый узел в последовательности.
|
||
|
||
\`
|
||
|
||
Циркулярный список ссылок
|
||
|
||
* * *
|
||
```
|
||
head
|
||
|
|
||
|
|
||
+-----+--+ +-----+--+ +-----+--+
|
||
```
|
||
|
||
\-> | 1 | o -----> | 2 | o -----> | 3 | o ----
|
||
| + ----- + - + + ----- + - + + ----- + - + |
|
||
| |
|
||
|
||
* * *
|
||
|
||
\`
|
||
|
||
**заявка**
|
||
|
||
Задача тайм-решетки, решаемая операционной системой.
|
||
|
||
В среде с временным разделением операционная система должна поддерживать список существующих пользователей и должна попеременно разрешать каждому пользователю использовать небольшую часть времени процессора, по одному пользователю за раз. Операционная система выберет пользователя, позволит ему использовать небольшое количество процессорного времени, а затем перейти к следующему пользователю.
|
||
|
||
Для этого приложения не должно быть указателей NULL, если нет абсолютно никакого запроса на процессорное время, то есть список пуст.
|
||
|
||
## Основные операции
|
||
|
||
1. вставка
|
||
|
||
Чтобы добавить новый элемент в список.
|
||
|
||
\`
|
||
|
||
Вставка в начале
|
||
|
||
* * *
|
||
|
||
* Создайте новый узел с данными.
|
||
* Наведите новый узел `next` со старой `head` .
|
||
* Направьте `head` на этот новый узел.
|
||
|
||
Вставка в середине / конце
|
||
|
||
* * *
|
||
|
||
Вставка после узла X.
|
||
|
||
* Создайте новый узел с данными.
|
||
* Наведите новый узел `next` со старым X `next` .
|
||
* Точка X находится `next` с этим новым узлом.
|
||
\`
|
||
|
||
**Сложность времени: O (1)**
|
||
|
||
1. делеция
|
||
|
||
Чтобы удалить существующий элемент из списка.
|
||
|
||
\`
|
||
|
||
Исключение в начале
|
||
|
||
* * *
|
||
|
||
* Возьмите узел, указанный `head` как Temp.
|
||
* Направьте `head` на `next` .
|
||
* Свободная память, используемая узлом Temp.
|
||
|
||
Удаление в середине / конце
|
||
|
||
* * *
|
||
|
||
Удаление после узла X.
|
||
|
||
* Получите узел, обозначенный `X` как Temp.
|
||
* Точка Икс `next` с Temp - х `next` .
|
||
* Свободная память, используемая узлом Temp.
|
||
\`
|
||
|
||
**Сложность времени: O (1)**
|
||
|
||
1. Пересекая
|
||
|
||
Перемещение по списку.
|
||
|
||
\`
|
||
|
||
пересечение
|
||
|
||
* * *
|
||
|
||
* Возьмите узел, указанный `head` как Текущий.
|
||
* Проверьте, не текут ли ток и отобразите его.
|
||
* Направьте ток в ток - х `next` и перейти к шагу выше.
|
||
\`
|
||
|
||
**Сложность времени: O (n) // Здесь n - размер списка ссылок**
|
||
|
||
## Реализация
|
||
|
||
### Реализация односвязного списка на C ++
|
||
```
|
||
// Header files
|
||
#include <iostream>
|
||
|
||
struct node
|
||
{
|
||
int data;
|
||
struct node *next;
|
||
};
|
||
|
||
// Head pointer always points to first element of the linked list
|
||
struct node *head = NULL;
|
||
```
|
||
|
||
#### Печать данных в каждом узле
|
||
```
|
||
// Display the list
|
||
void printList()
|
||
{
|
||
struct node *ptr = head;
|
||
|
||
// Start from the beginning
|
||
while(ptr != NULL)
|
||
{
|
||
std::cout << ptr->data << " ";
|
||
ptr = ptr->next;
|
||
}
|
||
|
||
std::cout << std::endl;
|
||
}
|
||
```
|
||
|
||
#### Вставка в начале
|
||
```
|
||
// Insert link at the beginning
|
||
void insertFirst(int data)
|
||
{
|
||
// Create a new node
|
||
struct node *new_node = new struct node;
|
||
|
||
new_node->data = data;
|
||
|
||
// Point it to old head
|
||
new_node->next = head;
|
||
|
||
// Point head to new node
|
||
head = new_node;
|
||
|
||
std::cout << "Inserted successfully" << std::endl;
|
||
}
|
||
```
|
||
|
||
#### Исключение в начале
|
||
```
|
||
// Delete first item
|
||
void deleteFirst()
|
||
{
|
||
// Save reference to head
|
||
struct node *temp = head;
|
||
|
||
// Point head to head's next
|
||
head = head->next;
|
||
|
||
// Free memory used by temp
|
||
temp = NULL:
|
||
delete temp;
|
||
|
||
std::cout << "Deleted successfully" << std::endl;
|
||
}
|
||
```
|
||
|
||
#### Размер
|
||
```
|
||
// Find no. of nodes in link list
|
||
void size()
|
||
{
|
||
int length = 0;
|
||
struct node *current;
|
||
|
||
for(current = head; current != NULL; current = current->next)
|
||
{
|
||
length++;
|
||
}
|
||
|
||
std::cout << "Size of Linked List is " << length << std::endl;
|
||
}
|
||
```
|
||
|
||
#### поиск
|
||
```
|
||
// Find node with given data
|
||
void find(int data){
|
||
|
||
// Start from the head
|
||
struct node* current = head;
|
||
|
||
// If list is empty
|
||
if(head == NULL)
|
||
{
|
||
std::cout << "List is empty" << std::endl;
|
||
return;
|
||
}
|
||
|
||
// Traverse through list
|
||
while(current->data != data){
|
||
|
||
// If it is last node
|
||
if(current->next == NULL){
|
||
std::cout << "Not Found" << std::endl;
|
||
return;
|
||
}
|
||
else{
|
||
// Go to next node
|
||
current = current->next;
|
||
}
|
||
}
|
||
|
||
// If data found
|
||
std::cout << "Found" << std::endl;
|
||
}
|
||
```
|
||
|
||
#### Удаление после узла
|
||
```
|
||
// Delete a node with given data
|
||
void del(int data){
|
||
|
||
// Start from the first node
|
||
struct node* current = head;
|
||
struct node* previous = NULL;
|
||
|
||
// If list is empty
|
||
if(head == NULL){
|
||
std::cout << "List is empty" << std::endl;
|
||
return ;
|
||
}
|
||
|
||
// Navigate through list
|
||
while(current->data != data){
|
||
|
||
// If it is last node
|
||
if(current->next == NULL){
|
||
std::cout << "Element not found" << std::endl;
|
||
return ;
|
||
}
|
||
else {
|
||
// Store reference to current node
|
||
previous = current;
|
||
// Move to next node
|
||
current = current->next;
|
||
}
|
||
|
||
}
|
||
|
||
// Found a match, update the node
|
||
if(current == head) {
|
||
// Change head to point to next node
|
||
head = head->next;
|
||
}
|
||
else {
|
||
// Skip the current node
|
||
previous->next = current->next;
|
||
}
|
||
|
||
// Free space used by deleted node
|
||
current = NULL;
|
||
delete current;
|
||
std::cout << "Deleted succesfully" << std::endl;
|
||
}
|
||
```
|
||
|
||
![:rocket:](https://forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=3 ": Ракета:") [Код запуска](https://repl.it/CXVt/1)
|
||
|
||
### Python Реализация единого связанного списка
|
||
```
|
||
class Node(object):
|
||
# Constructor
|
||
def __init__(self, data=None, next=None):
|
||
self.data = data
|
||
self.next = next
|
||
|
||
# Function to get data
|
||
def get_data(self):
|
||
return self.data
|
||
|
||
# Function to get next node
|
||
def get_next(self):
|
||
return self.next
|
||
|
||
# Function to set next field
|
||
def set_next(self, new_next):
|
||
self.next = new_next
|
||
class LinkedList(object):
|
||
def __init__(self, head=None):
|
||
self.head = head
|
||
```
|
||
|
||
#### вставка
|
||
```
|
||
# Function to insert data
|
||
def insert(self, data):
|
||
# new_node is a object of class Node
|
||
new_node = Node(data)
|
||
new_node.set_next(self.head)
|
||
self.head = new_node
|
||
print("Node with data " + str(data) + " is created succesfully")
|
||
```
|
||
|
||
#### Размер
|
||
```
|
||
# Function to get size
|
||
def size(self):
|
||
current = self.head
|
||
count = 0
|
||
while current:
|
||
count += 1
|
||
current = current.get_next()
|
||
print("Size of link list is " + str(count))
|
||
```
|
||
|
||
#### поиск
|
||
```
|
||
# Function to search a data
|
||
def search(self, data):
|
||
current = self.head
|
||
found = False
|
||
while current and found is False:
|
||
if current.get_data() == data:
|
||
found = True
|
||
else:
|
||
current = current.get_next()
|
||
if current is None:
|
||
print("Node with data " + str(data) + " is not present")
|
||
else:
|
||
print("Node with data " + str(data) + " is found")
|
||
```
|
||
|
||
#### Удаление после узла
|
||
```
|
||
# Function to delete a node with data
|
||
def delete(self, data):
|
||
current = self.head
|
||
previous = None
|
||
found = False
|
||
while current and found is False:
|
||
if current.get_data() == data:
|
||
found = True
|
||
else:
|
||
previous = current
|
||
current = current.get_next()
|
||
if current is None:
|
||
print("Node with data " + str(data) + " is not in list")
|
||
elif previous is None:
|
||
self.head = current.get_next()
|
||
print("Node with data " + str(data) + " is deleted successfully")
|
||
else:
|
||
previous.set_next(current.get_next())
|
||
print("Node with data " + str(data) + " is deleted successfully")
|
||
```
|
||
|
||
![:rocket:](//forum.freecodecamp.com/images/emoji/emoji_one/rocket.png?v=2 ": Ракета:") [Код запуска](https://repl.it/CVq3/2)
|
||
|
||
**преимущества**
|
||
|
||
1. Связанные списки - это динамическая структура данных, которая может расти и сокращаться, выделять и освобождать память во время работы программы.
|
||
2. Вставка и удаление узла легко реализуются в связанном списке в любой позиции.
|
||
|
||
**Недостатки**
|
||
|
||
1. Они используют больше памяти, чем массивы, из-за памяти, используемой их указателями ( `next` and `prev` ).
|
||
2. Случайный доступ в связанном списке невозможен. Мы должны последовательно обращаться к узлам.
|
||
3. Это сложнее, чем массив. Если язык автоматически поддерживает привязку массива, массивы будут служить вам лучше.
|
||
|
||
#### Заметка
|
||
|
||
Мы должны использовать free () в C и удалять на C ++ для освобождения пространства, используемого удаленным узлом, тогда как в Python и Java свободное пространство автоматически собирается сборщиком мусора. |