Sök…


Introduktion till länkade listor

En länkad lista är en linjär samling av dataelement, kallad noder, som är länkade till andra nod (er) med hjälp av en "pekare". Nedan finns en enskilt länkad lista med en huvudreferens.

         ┌─────────┬─────────┐   ┌─────────┬─────────┐         
 HEAD ──▶│  data   │"pointer"│──▶│  data   │"pointer"│──▶ null 
         └─────────┴─────────┘   └─────────┴─────────┘         

Det finns många typer av länkade listor, inklusive enskilda och dubbelt länkade listor och cirkulära länkade listor.

fördelar

  • Länkade listor är en dynamisk datastruktur som kan växa och krympa, allokera och omlokalisera minne medan programmet körs.

  • Insättnings- och raderingsoperationer för nod implementeras enkelt i en länkad lista.

  • Linjära datastrukturer som staplar och köer implementeras enkelt med en länkad lista.

  • Länkade listor kan minska åtkomsttiden och kan expanderas i realtid utan minneskostnader.

Singellänkad lista

Singellänkade listor är en typ av länkad lista . En enda länkade listans noder har bara en "pekare" till en annan nod, vanligtvis "nästa." Det kallas en enskilt länkad lista eftersom varje nod bara har en enda "pekare" till en annan nod. En enskilt länkad lista kan ha en huvud- och / eller svansreferens. Fördelen med att ha en getFromBack är getFromBack , addToBack och removeFromBack fall som blir O (1).

         ┌─────────┬─────────┐   ┌─────────┬─────────┐         
 HEAD ──▶│  data   │"pointer"│──▶│  data   │"pointer"│──▶ null 
         └─────────┴────△────┘   └─────────┴─────────┘         
          SINGLE        │                                      
          REFERENCE ────┘                                                                

Exempelkod i C

Exempel Kod i Java, med enhetstester - enskilt länkad lista med huvudreferens

XOR-länkad lista

En XOR-länkad lista kallas också en minneseffektiv länkad lista . Det är en annan form av en dubbel länkad lista. Detta är mycket beroende av XOR- logiken och dess egenskaper.

Varför kallas detta minneseffektiv länkad lista?

Detta kallas så eftersom det använder mindre minne än en traditionell dubbelkopplad lista.


Är det annorlunda från en dubbel länkad lista?

Ja , det är det.

En dubbelkopplad lista lagrar två pekare som pekar på nästa och föregående nod. I grund och botten, om du vill gå tillbaka, går du till den adress som indikeras av back pekaren. Om du vill gå framåt går du till adressen som pekas av next pekare. Det är som:

ange bildbeskrivning här

En minneseffektiv länkad lista , eller nämligen XOR-länkad lista har bara en pekare istället för två. Detta lagrar den föregående adressen (addr (föregående)) XOR (^) nästa adress (addr (nästa)). När du vill flytta till nästa nod gör du vissa beräkningar och hittar adressen till nästa nod. Detta är samma sak för att gå till föregående nod. Det är som:

ange bildbeskrivning här


Hur fungerar det?

För att förstå hur den länkade listan fungerar måste du känna till XOR (^):

|-------------|------------|------------|
|    Name     |   Formula  |    Result  |
|-------------|------------|------------|
| Commutative |    A ^ B   |    B ^ A   |
|-------------|------------|------------|
| Associative | A ^ (B ^ C)| (A ^ B) ^ C|
|-------------|------------|------------|
| None (1)    |    A ^ 0   |     A      |
|-------------|------------|------------|
| None (2)    |    A ^ A   |     0      |
|-------------|------------|------------|
| None (3)    | (A ^ B) ^ A|     B      |
|-------------|------------|------------|

Låt oss nu lämna detta åt sidan och se vad varje nod lagrar.

Den första noden, eller huvudet , lagrar 0 ^ addr (next) eftersom det inte finns någon tidigare nod eller adress. Det ser ut så här .

Sedan lagrar den andra noden addr (prev) ^ addr (next) . Det ser ut så här .

Listans svans har ingen nästa nod, så den lagrar addr (prev) ^ 0 . Det ser ut så här .

Flytta från huvudet till nästa nod

Låt oss säga att du är nu vid den första noden eller vid nod A. Nu vill du flytta vid nod B. Detta är formeln för att göra det:

Address of Next Node = Address of Previous Node ^ pointer in the current Node

Så detta skulle vara:

addr (next) = addr (prev) ^ (0 ^ addr (next))

Eftersom detta är huvudet, skulle den tidigare adressen helt enkelt vara 0, så:

addr (next) = 0 ^ (0 ^ addr (next))

Vi kan ta bort parenteserna:

addr (next) = 0 ^ 0 addr (next)

Med hjälp av none (2) -egenskapen kan vi säga att 0 ^ 0 alltid kommer att vara 0:

addr (next) = 0 ^ addr (next)

Med egenskapen none (1) kan vi förenkla den till:

addr (next) = addr (next)

Du har adressen till nästa nod!

Flytta från en nod till nästa nod

Låt oss nu säga att vi befinner oss i en mittnod som har en föregående och nästa nod.

Låt oss använda formeln:

Address of Next Node = Address of Previous Node ^ pointer in the current Node

Byt nu ut värdena:

addr (next) = addr (prev) ^ (addr (prev) ^ addr (next))

Ta bort pareteser:

addr (next) = addr (prev) ^ addr (prev) ^ addr (next)

Med egenskapen none (2) kan vi förenkla:

addr (next) = 0 ^ addr (next)

Med egenskapen none (1) kan vi förenkla:

addr (next) = addr (next)

Och du får det!

Flytta från en nod till den nod du befann dig tidigare

Om du inte förstår titeln betyder det i princip att om du befann dig i nod X och nu har flyttat till nod Y, vill du gå tillbaka till den nod som besökts tidigare, eller i princip node X.

Detta är inte en besvärlig uppgift. Kom ihåg att jag nämnde ovan, att du lagrar adressen du var på i en tillfällig variabel. Så adressen till den nod du vill besöka ligger i en variabel:

addr (prev) = temp_addr

Flytta från en nod till föregående nod

Detta är inte samma sak som nämnts ovan. Jag menar att säga att du var vid nod Z, nu är du vid nod Y och vill gå till nod X.

Detta är nästan samma sak som att flytta från en nod till nästa nod. Bara att det här är det tvärtom. När du skriver ett program använder du samma steg som jag nämnde vid flyttningen från en nod till nästa nod, bara för att du hittar det tidigare elementet i listan än att hitta nästa element.


Exempelkod i C

/* C/C++ Implementation of Memory efficient Doubly Linked List */
#include <stdio.h>
#include <stdlib.h>
 
// Node structure of a memory efficient doubly linked list
struct node
{
    int data;
    struct node* npx;  /* XOR of next and previous node */
};
 
/* returns XORed value of the node addresses */
struct node* XOR (struct node *a, struct node *b)
{
    return (struct node*) ((unsigned int) (a) ^ (unsigned int) (b));
}
 
/* Insert a node at the begining of the XORed linked list and makes the
   newly inserted node as head */
void insert(struct node **head_ref, int data)
{
    // Allocate memory for new node
    struct node *new_node  = (struct node *) malloc (sizeof (struct node) );
    new_node->data = data;
 
    /* Since new node is being inserted at the begining, npx of new node
       will always be XOR of current head and NULL */
    new_node->npx = XOR(*head_ref, NULL);
 
    /* If linked list is not empty, then npx of current head node will be XOR 
       of new node and node next to current head */
    if (*head_ref != NULL)
    {
        // *(head_ref)->npx is XOR of NULL and next. So if we do XOR of 
        // it with NULL, we get next
        struct node* next = XOR((*head_ref)->npx,  NULL);
        (*head_ref)->npx = XOR(new_node, next);
    }
 
    // Change head
    *head_ref = new_node;
}
 
// prints contents of doubly linked list in forward direction
void printList (struct node *head)
{
    struct node *curr = head;
    struct node *prev = NULL;
    struct node *next;
 
    printf ("Following are the nodes of Linked List: \n");
 
    while (curr != NULL)
    {
        // print current node
        printf ("%d ", curr->data);
 
        // get address of next node: curr->npx is next^prev, so curr->npx^prev
        // will be next^prev^prev which is next
        next = XOR (prev, curr->npx);
 
        // update prev and curr for next iteration
        prev = curr;
        curr = next;
    }
}
 
// Driver program to test above functions
int main ()
{
    /* Create following Doubly Linked List
       head-->40<-->30<-->20<-->10   */
    struct node *head = NULL;
    insert(&head, 10);
    insert(&head, 20);
    insert(&head, 30);
    insert(&head, 40);
 
    // print the created list
    printList (head);
 
    return (0);
}

Ovanstående kod utför två grundläggande funktioner: insättning och tvärgående.

  • Införande: Detta sker genom funktionen insert . Detta sätter in en ny nod i början. När den här funktionen anropas sätter den den nya noden som huvud och den föregående huvudnoden som den andra noden.

  • Traversal: Detta utförs av funktionen printList . Den går helt enkelt genom varje nod och skriver ut värdet.

Observera att XOR för pekare inte definieras av C / C ++ -standarden. Så ovanstående implementering kanske inte fungerar på alla plattformar.


referenser

Observera att jag har tagit mycket innehåll från mitt eget svar i huvudsak.

Hoppa över listan

Hoppa över listor är länkade listor som låter dig hoppa till rätt nod. Detta är en metod som är mycket snabbare än en vanlig singellänkad lista. Det är i princip en enskilt länkad lista men pekarna går inte från en nod till nästa nod, utan hoppar över några noder. Således namnet "Skip List".


Är detta annorlunda från en singellänkad lista?

Ja , det är det.

En singellänkad lista är en lista med varje nod som pekar till nästa nod. En grafisk representation av en enskilt länkad lista är som:

ange bildbeskrivning här

En hopplista är en lista med varje nod som pekar på en nod som kanske eller inte kan vara efter den. En grafisk representation av en hopplista är:

ange bildbeskrivning här


Hur fungerar det?

Hoppa över listan är enkel. Låt oss säga att vi vill komma åt nod 3 i bilden ovan. Vi kan inte ta vägen att gå från huvudet till den fjärde noden, eftersom det är efter den tredje noden. Så vi går från huvudet till den andra noden och sedan till den tredje.

En grafisk representation är som:

ange bildbeskrivning här


referenser

Dubbel länkad lista

Dubbelbundna listor är en typ av länkad lista . En dubbel länkad listans noder har två "pekare" till andra noder, "nästa" och "föregående." Det kallas en dubbellänkad lista eftersom varje nod bara har två "pekare" till andra noder. En dubbel länkad lista kan ha en huvud- och / eller svanspekare.

         ┌─────────┬─────────┬─────────┐   ┌─────────┬─────────┬─────────┐         
 null ◀──┤previous │  data   │  next   │◀──┤previous │  data   │  next   │         
         │"pointer"│         │"pointer"│──▶│"pointer"│         │"pointer"│──▶ null 
         └─────────┴─────────┴─────────┘   └─────────┴─────────┴─────────┘         
                          ▲                     △                   △              
                     HEAD │                     │     DOUBLE        │              
                                                └──── REFERENCE ────┘                 

Dubbelbundna listor är mindre utrymmeeffektiva än enskilda länkade listor; för vissa operationer erbjuder de dock betydande förbättringar i tidseffektivitet. Ett enkelt exempel är get funktionen, som för en dubbel länkad lista med en huvud- och svansreferens kommer att börja från huvud eller svans beroende på index för elementet som ska fås. För en n elementlista, för att få det n/2 + i indexerade elementet, måste en enskilt länkad lista med huvud / svansreferenser gå igenom n/2 + i noder, eftersom den inte kan "gå tillbaka" från svansen. En dubbel länkad lista med huvud- / svansreferenser måste bara korsa n/2 - i noder, eftersom den kan "gå tillbaka" från svansen och korsa listan i omvänd ordning.

Exempelkod i C

Ett grundläggande SinglyLinkedList-exempel i Java

En grundläggande implementering för enskilt länkad lista i java - som kan lägga till heltalvärden i slutet av listan, ta bort det första värdet som uppstått från listan, returnera en matris med ett visst ögonblick och bestämma om ett givet värde är närvarande i listan.

Node.java

package com.example.so.ds;


/**
 * <p> Basic node implementation </p>
 * @since 20161008
 * @author Ravindra HV
 * @version 0.1
 */
public class Node {
    
    private Node next;
    private int value;
    
    public Node(int value) {
        this.value=value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    public int getValue() {
        return value;
    }
    
    
}

SinglyLinkedList.java

package com.example.so.ds;


/**
 * <p> Basic single-linked-list implementation </p>
 * @since 20161008
 * @author Ravindra HV
 * @version 0.2
 */
public class SinglyLinkedList {
    
    private Node head;
    private volatile int size;
    
    public int getSize() {
        return size;
    }
    
    public synchronized void append(int value) {
        
        Node entry = new Node(value);
        if(head == null) {
            head=entry;
        }
        else {
            Node temp=head;
            while( temp.getNext() != null) {
                temp=temp.getNext();
            }
            temp.setNext(entry);
        }
        
        size++;
    }
    
    
    public synchronized boolean removeFirst(int value) {
        boolean result = false;
        
        if( head == null ) { // or size is zero..
            // no action
        }
        else if( head.getValue() == value ) {
            head = head.getNext();
            result = true;
        }
        else {

            Node previous = head;
            Node temp = head.getNext();
            while( (temp != null) && (temp.getValue() != value) ) {
                previous = temp;
                temp = temp.getNext();
            }
            
            if((temp != null) && (temp.getValue() == value)) { // if temp is null then not found..
                previous.setNext( temp.getNext() );
                result = true;
            }

        }
        
        if(result) {
            size--;
        }
        
        return result;
        
    }
    
    public synchronized int[] snapshot() {
        Node temp=head;
        int[] result = new int[size];
        for(int i=0;i<size;i++) {
            result[i]=temp.getValue();
            temp = temp.getNext();
        }
        return result;
    }
    
    public synchronized boolean contains(int value) {
        boolean result = false;
        Node temp = head;
        
        while(temp!=null) {
            if(temp.getValue() == value) {
                result=true;
                break;
            }
            temp=temp.getNext();
        }
        return result;
    }
    
}

TestSinglyLinkedList.java

package com.example.so.ds;

import java.util.Arrays;
import java.util.Random;


/**
 * 
 * <p> Test-case for single-linked list</p>
 * @since 20161008
 * @author Ravindra HV
 * @version 0.2
 *
 */
public class TestSinglyLinkedList {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        SinglyLinkedList singleLinkedList = new SinglyLinkedList();
        
        int loop = 11;
        Random random = new Random();
        
        for(int i=0;i<loop;i++) {
            
            int value = random.nextInt(loop);
            singleLinkedList.append(value);

            System.out.println();
            System.out.println("Append :"+value);
            System.out.println(Arrays.toString(singleLinkedList.snapshot()));
            System.out.println(singleLinkedList.getSize());
            System.out.println();
        }
        
        for(int i=0;i<loop;i++) {
            int value = random.nextInt(loop);
            boolean contains = singleLinkedList.contains(value);
            singleLinkedList.removeFirst(value);
            
            System.out.println();
            System.out.println("Contains :"+contains);
            System.out.println("RemoveFirst :"+value);
            System.out.println(Arrays.toString(singleLinkedList.snapshot()));
            System.out.println(singleLinkedList.getSize());
            System.out.println();
        }
        

    }

}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow