Рубрики
Без рубрики

Связанный список против массива

Связанный список и массив, вероятно, являются наиболее основными структурами данных, но их использование часто может быть запутано. Использование соответствующей структуры данных может

Автор оригинала: Pankaj Kumar.

Связанный список и массив, вероятно, являются наиболее основными структурами данных, но их использование часто может быть запутано. Использование соответствующей структуры данных может часто приводить к более прощему и более эффективному коду. Связанный список VS Array также является популярным интервью в структурах данных.

Связанный список против массива

Эта статья предоставит углубленное сравнение этих двух структур данных.

Мы сравним их на основе следующих свойств:

  • Определения и структуры
  • Операции и анализ сложности времени
  • Анализ памяти
  • Коды (C и Python)

1. Определения и структуры

Связанный список – это структура данных, которая хранит линейно подключенные, нереационные данные через ссылки. Это означает, что каждый узел связанного списка будет содержать ссылку на его следующий и/или предыдущий узел. Это помогает сделать цепочку узлов, которые линейно связаны, но в памяти они могут не быть в смежном сегменте.

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

В памяти массивы также присутствуют в смежном блоке данных.

2D массивы

2. Анализ сложности работы и времени

Мы будем сравнивать структуры данных, основанные на следующих операциях:

  • Вставка и удаление
  • Доступ к элементам

Вставка и удаление

Вставка и удаление в связанном списке могут быть выполнены в начале, в середине или в конце.

  • Если в начале выполняется вставка или удаление, то нам просто нужно переназначить ссылки на голову, таким образом, это операция O (1).
  • Если вставка или удаление выполнено в середине или в конце, то сначала нам необходимо добраться до необходимого положения в O (N), а затем переназначить ссылки в O (1) время. Это принимает o (n + (n) время.

Связанный список вставка

Для массива, везде, где выполняется вставка или удаление, нам всегда нужно перемещать остаток массива, чтобы сбалансировать индексацию, таким образом, эти операции принимают O (1) время для выполнения операции и O (N) для балансировки индексации. Таким образом, требуется O (N + (N) время всегда.

Вставка массива

Доступ к элементам

В связанном списке для доступа к элементу мы должны достичь его позиции через обход с начала, который принимает o (n) время.

В массиве у нас есть индексы, к которым мы можем напрямую обращаться. Это полезно, потому что теперь нам не нужно делать обход, и, таким образом, доступ к тому, что принимает время O (1).

3. Анализ памяти

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

Массивы с другой стороны, всегда имеют фиксированный размер. Если элемент не назначается никакого значения, то он по-прежнему остается частью массива и все равно будет использовать память.

Но это не означает, что массивы всегда менее эффективны. Массивы занимают только память, которую они назначены, тогда как связанный список примет память для хранения данных, а также хранения ссылок. Кроме того, для некоторых операций, таких как сортировка, нам нужно дополнительное место для хранения и сдвига элементов, что эффективно в массивах.

Связанные реализации списка

1. Питон

class Node:

    def __init__(self, data):
        self.data = data
        self.next = None


class LinkedList:
    """
    Initialize the list by assigning
    head = NULL.
    """

    def __init__(self):
        self.head = None

    '''
    Returns the linear traversal of the
    Linked List in the form of a list.

    Initially, we can define a node that 
    points to the head of the linked list
    and then we can keep sending it forward 
    in the Linked List till we don't hit an end.
    '''

    def traverse_list(self):

        # Node that points to the head, initially.
        cur = self.head
        ret = []

        # Loop to send the cur node to the end.
        while cur:
            ret.append(cur.data)
            cur = cur.next

        # Returns the Linear Traversal in a list.
        return ret

    '''
    To insert a node, we have 3 cases:
    1) Empty List
    2) Insertion at the beginning
    3) Insertion in the middle/at the end

    For insertion at the end, we can loop till
    one element before the required position 
    and then do the relinking of references.
    '''

    def insert_node(self, pos, data):

        new_node = Node(data)
        cur_node = self.head

        # Case 1 : Empty List
        if cur_node is None:
            self.head = new_node

        # Case 2: Insertion at the beginning
        elif pos == 0:
            new_node.next = self.head
            self.head = new_node

        # Case 3: Insertion in the middle/at the end
        else:
            while pos - 1 > 0 and cur_node.next is not None:
                cur_node = cur_node.next
                pos -= 1

            next_node = cur_node.next
            new_node.next = next_node
            cur_node.next = new_node

        return True

    '''
    To delete a node, we have 5 cases:
    1) Deletion from Empty List
    2) Deletion at the beginning
    5) Delete a node that does not exist
    3) Deletion at the end
    4) Deletion in the middle

    For deletion of a node, we first reach
    one node before the required position
    through a linear traversal and then relink
    the references accordingly.
    '''

    def remove_node(self, pos):

        # Case 1 : Empty List
        if self.head is None:
            return False

        # Case 2 : Deletion at beginning
        elif pos == 0:
            self.head = self.head.next
            return True

        else:
            cur = self.head
            while pos - 1 > 0 and cur is not None:
                cur = cur.next
                pos -= 1

            # Case 3 : Delete a node that does not exist
            if cur is None:
                return False

            # Case 4: Deletion at the end
            elif cur.next is None:
                cur = self.head
                while cur.next.next is not None:
                    cur = cur.next
                cur.next = None
                return True

            # Case 5 : Deletion in the middle
            cur.next = cur.next.next
            return True


a = LinkedList()
a.insert_node(0, 3)
a.insert_node(0, 2)
a.insert_node(0, 1)
print("Linked List :", a.traverse_list())
a.remove_node(2)
print("Linked list :", a.traverse_list())

Выход

2. C.

#include
#include
#include

struct node{
    int data;
    struct node *next;
} *head = NULL;

struct node *make_node(int data){
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->next = NULL; 
    new->data = data;
    return new;
}

/*
To insert a node, we have 3 cases:
1) Empty List
2) Insertion at the beginning
3) Insertion in the middle/at the end

For insertion at the end, we can loop till
one element before the required position 
and then do the relinking of references.
*/

bool insertNode(int pos, int data){
    struct node *newNode = make_node(data), *curNode = head;

    //Case 1 : Empty List
    if(curNode == NULL){
        head = newNode;
    }

    //Case 2: Insertion at the beginning
    else if(pos == 0){
        newNode->next = head;
        head = newNode;
    }

    //Case 3: Insertion in the middle/at the end
    else{
        while(pos - 1 > 0 && curNode->next != NULL){
            curNode = curNode->next;
            pos--;
        }
        newNode->next = curNode->next;
        curNode->next = newNode;
    }

    return true;
}

/*
Initially we can define a node that 
points to the head of the linked list
and then we can keep sending it forward 
in the Linked List till we don't hit an end.
*/
void traverseList(){
    struct node *cur = head;
    while(cur){
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

/*
To delete a node, we have 5 cases:
1) Deletion from Empty List
2) Deletion at the beginning
5) Delete a node that does not exist
3) Deletion at the end
4) Deletion in the middle

For deletion of a node, we first reach
one node before the required position
through a linear traversal and then relink
the references accordingly.
*/

bool removeNode(int pos){

    struct node *cur;

    //Case 1 : Empty List
    if(head == NULL)
        return false;

    //Case 2 : Deletion at beginning
    else if (pos == 0){
        head = head->next;
        return true;
    }

    else{

        cur = head;
        while (pos - 1 > 0 && cur != NULL){
            cur = cur->next;
            pos--;
        }

        //Case 3 : Delete a node that does not exist
        if(cur == NULL)
            return false;

        //Case 4: Deletion at the end
        else if(cur->next == NULL){
            cur = head;
            while(cur->next->next != NULL){
                cur = cur->next;
            }
            cur->next = NULL;
            return true;
        }

        //Case 5 : Deletion in the middle
        cur->next = cur->next->next;
        return true;
    }
}

int main(){

    insertNode(0, 3);
    insertNode(0, 2);
    insertNode(0, 1);

    traverseList();
    removeNode(3);
    traverseList();

    return 0;
}

Выход

Реализации массивов

1. Питон

N = 10
singleDimensionalArray = [0 for i in range(N)]
multiDimensionalArray = [[0 for x in range(N)] for y in range(N)]

A = 4
pos = 5
singleDimensionalArray[pos] = A

X, Y = 2, 3
multiDimensionalArray[X][Y] = A

print(singleDimensionalArray)

for i in multiDimensionalArray:
    print(i)

Выход :

2. C.

#include
#include
#include

#define N 5

int main(){

    int singleDimensionalArray[N] = {0};
    int multiDimensionalArray[N][N] = {0};

    int A = 4;
    int pos = 3, X = 2, Y = 3;

    singleDimensionalArray[pos] = A;
    multiDimensionalArray[X][Y] = A;

    int i, j;
    for(i = 0; i < N; i++){
        printf("%d ", singleDimensionalArray[i]);
    }
    printf("\n\n");

    for(i = 0; i < N; i++){
        for(j = 0; j < N; j++){
            printf("%d ", multiDimensionalArray[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Выход