Detailed summary of linear table (array, linked list, queue, stack)

Linear table is a very basic and important data structure, which mainly includes the following contents:

  • array
  • Linked list
  • queue
  • Stack

Next, I will make a detailed summary of these four data structures, including more than a dozen common operations on the linked list. I hope it will help you.

1. Array

Array is a linear table data structure. It uses a continuous set of memory space to store a set of data of the same type.
Note: ①. Array is a linear table; ②. Continuous memory space and data of the same type
Because of the second property, the array supports "random access". According to the following table, the time complexity of random access is O(1); however, at the same time, it makes it necessary to delete the data in the array and insert a large amount of data movement work.

Inefficient "insert" and "delete"

Insert operation

If the length of the array is n, we need to insert a data into the k position of the array. We need to move the k~n elements back one bit in order.
In the best case, the time complexity is O(1), which corresponds to inserting elements at the end of the array;
In the worst case, the time complexity is O(n), which corresponds to inserting elements at the beginning of the array;
The average time complexity is O (n), because we have the same probability of inserting elements in each position, so (1 + 2 + 3 +...) +n)/n=O(n);
But according to our needs, there is a specific scenario. If the data of the array is orderly, we must do so when inserting it; but if the data stored in the array has no rules, the array is just regarded as a collection of stored data, we can have a shortcut:
Move the k-th element directly to the end of the array element, and put the new data directly in the k-th position (isn't it very simple). At this time, the complexity of inserting the element is O(1).

Delete operation

As with the insert operation, in order to ensure the continuity of memory, the delete operation also needs to move data.
In the best case, the time complexity is O(1), which means deleting the elements at the end of the array;
In the worst case, the time complexity is O(n), which corresponds to the deletion of the elements at the beginning of the array;
The average case time complexity is O (n), because we have the same probability to delete elements in each position, so (1 + 2 + 3 +...) +n)/n=O(n);
Of course, in some special cases, we do not have to carry out complex delete operations. We just delete the data record and pretend it has been deleted. Until the array does not have more space to store data, we can trigger a real delete operation.

In fact, it is similar to the garbage can in our life. The garbage does not disappear, but is marked as garbage. The garbage can not be cleaned until it is full.

Beware of array access out of bounds

In C language, all memory spaces can be accessed freely as long as they are not limited. If you neglect, you will have serious consequences. Of course, Java automatically detects it.

2. List

  • Link list node representation
  • Print single chain table
  • Single chain table inserts nodes according to index
  • Get the length of a single linked table
  • Print the length of a single linked table
  • Single chain table delete node of specified index
  • Single chain table implements element lookup and returns whether there is a Boolean value
  • Single linked table delete subsequent nodes of specified index
  • Single chain table inversion
  • Recursive single chain table inversion
  • Check whether there are links in the list
  • Delete the last k nodes
  • Find the middle node
  • Ordered list merging

Link list node representation

public class Node{
    int data;
    Node Next;
}

Print single chain table

public class Method {
    //Print single chain table
    public static void PrintNode (Node list){
        for(Node x=list;x!=null;x=x.Next)
        System.out.print(x.data+" ");
        System.out.println();
    }

Single chain table inserts nodes according to index

    public static Node insert(Node first,int index,Node a){
        Node ret = new Node();
        ret.Next=first;//Create a virtual head node
        Node p=ret;
        while((index--)!=0) p=p.Next;
        //Complete node insertion
        a.Next=p.Next;
        p.Next=a;
        //Return the real link header node address
        return ret.Next;//Function returns the head node of the linked list
    }

Get the length of a single linked table

    public static int GetLength(Node first){
        int n=0;
        for(Node x=first;x!=null;x=x.Next){
            ++n;
        }
        return n;
    }

Print the length of a single linked table

    public static void PrintLength(Node first){
        System.out.println("Length : "+GetLength(first));
    }

Single chain table delete node of specified index

    public static Node Delete(Node first,int index){
        if(index<0||index>=GetLength(first)) return first;
        else{
        Node ret=new Node();
        ret.Next=first;
        Node p=ret;
        while((index--)!=0) p=p.Next;
        //Delete node complete
        p.Next=p.Next.Next;
        return ret.Next;
        }
    }

Single chain table implements element lookup and returns whether there is a Boolean value

    public static boolean Find(Node first,int key){
        for(Node x=first;x!=null;x=x.Next){
            if(x.data==key) return true;
        }
        return false;
    }

Single linked table delete subsequent nodes of specified index

    public static void RemoveAfter(Node first,int index){
        Node ret=new Node();
        ret.Next=first;
        Node p=ret;
        while((index--)!=0) p=p.Next;
        p.Next.Next=null;

    }

Single chain table inversion

    public static Node  reverse(Node list){
        Node curr=list,pre=null;
        while(curr!=null){
            Node next=curr.Next;
            curr.Next=pre;
            pre=curr;
            curr=next;
        }
        return pre;
    }

Recursive single chain table inversion

    public static Node reverseRecursively(Node head){
        if(head==null||head.Next==null) return head;//Recursive termination condition, return the head node of the inverted linked list
        Node reversedListHead=reverseRecursively(head.Next);
        head.Next.Next=head;//Change the pointing order between the two nodes
        head.Next=null;
        return  reversedListHead;//Return to the reversed chain header node
    }

Check whether there are links in the list

    public static boolean checkCircle(Node list){
        if(list==null) return false;

        Node fast=list.Next;
        Node slow=list;

        while(fast!=null&&fast.Next!=null){
            fast=fast.Next.Next;
            slow=slow.Next;

            if(slow==fast) return true;
        }
        return false;
    }

Delete the last k nodes

    public static Node deleteLastKth(Node list,int k){
        //Using two pointers, fast and slow, the difference between them is k positions, to determine if fast.Nest=null , which means that the position of slow is the last K node
        Node fast=list;
        int i=1;
        while(fast!=null&&i<k){
            fast=fast.Next;
            ++i;
        }

        if(fast==null) return list;

        Node slow=list;
        Node prev=null;
        while(fast.Next!=null){
            fast=fast.Next;
            prev=slow;
            slow=slow.Next;
        }

        if(prev==null){
            list=list.Next;
        }else{
            prev.Next=prev.Next.Next;
        }
        return list;
    }

Find the middle node

    public static Node findMiddleNode(Node list){
        if(list==null) return null;

        Node fast=list;
        Node slow=list;

        while(fast!=null&&fast.Next!=null){
            fast=fast.Next.Next;
            slow=slow.Next;
        }

        return slow;
    }

Ordered list merging

    public static Node mergeTwoLists(Node l1,Node l2){
        Node soldier=new Node();
        Node p=soldier;

        while(l1!=null&&l2!=null){
            if(l1.data<l2.data){
                p.Next=l1;
                l1=l2.Next;
            }
            else{
                p.Next=l2;
                l2=l2.Next;
            }
            p=p.Next;
        }

        if(l1!=null){ p.Next=l1;}
        if(l2!=null){ p.Next=l2;}
        return soldier.Next;
    }

3. Stack

  • Sequence stack
  • Chain stack

1. Sequential stack based on array

  • Constructor
  • Push operation
  • Stack out operation
  • Print operation
package Stack;

//Array based sequential stack
public class ArrayStack {
    private int[] items;
    private int count;//Number of elements in the stack
    private int n;//Stack size
  //Initialize the array and request an array space of size n
public ArrayStack(int n){
    this.items=new int[n];
    this.n=n;
    this.count=0;
}

//Push operation
public boolean push(int item){
    //Insufficient array space, return false directly, failed to stack
    if(count==n) return false;
    //Place the data in the position with the subscript count, and add one to count
    items[count]=item;
    ++count;
    return true;
}

//Stack out operation
public int pop(){
    //Stack is empty, return to - 1 directly;
    if(count==0) return -1;
    //Returns the array element with the subscript count-1, and the number of elements in the stack count minus one
    int tmp=items[count-1];
    --count;
    return tmp;
}
public void PrintStack(){
    for(int i=count-1;i>=0;--i){
        System.out.print(items[i]+" ");
    }
    System.out.println();
    }
}

2. Linked stack based on linked list

  • Push operation
  • Stack out operation
  • Print operation
package Stack;

public class LinkedListStack {
    private Node top;//Top of stack (recently added element)
    private int N;//Number of elements
    private class Node{
        //The nested classes of nodes are defined
        int data;
        Node Next;
    }
    public boolean isEmpty(){
        return top==null;
    }
    public int size(){
        return N;
    }

    public void push(int data){
        /*Node newNode=new Node();
        //Judge whether it is an empty stack
        //if(top==null) 
        newNode=top;
        top.data=data;
        top.Next=newNode;
        N++;*/
        Node newNode=top;
        top=new Node();
        top.data=data;
        top.Next=newNode;
        ++N;
    }
    public int pop(){
        //Remove element from top of stack
        if(top==null) return -1;//Here - 1 means there is no data in the stack
        int data=top.data;
        top=top.Next;
        N--;
        return data;
    }
    public void PrintStack(){
        for(Node x=top;x!=null;x=x.Next){
            System.out.print(x.data+" ");
        }
        System.out.println();
    }

}

4. Normal queue

  • General queue based on array
  • Queue based on linked list
  • Circular queue based on array

1. Common queue based on array

  • Constructor
  • Entry operation
  • Out of line operation
  • Print elements in queue
package Queue;

//Using array to realize queue
public class ArrayQueue {
    //Array: items, array size: n
    private int[] items;
    private int n=0;
    //Head is the team's head and tail is the team's tail
    private int head=0;
    private int tail=0;

    //Request an array of size capacity
    public ArrayQueue(int capacity){
        items=new int[capacity];
        n=capacity;
    }

    //Team entry (I), basic version
    public boolean enqueue(int item){
        //If tail==n, there is no space at the end of the queue
        if(tail==n) return false;
        items[tail]=item;
        ++tail;
        return true;
    }

    //Team entry (2), improved version
    public boolean enqueue1(int item){
        //If tail==n, there is no space at the end of the queue
        if(tail==n){
            //Tail = = n & & head = = 0, indicating that the whole queue is full
            if(head==0) return false;
            //Data movement
            for(int i=head;i<tail;++i){
                items[i-head]=items[i];
            }
            //Update head and tail after move
            tail=tail-head;
            head=0;
        }
        items[tail]=item;
        ++tail;
        return true;
    }

    //Out of the team
    public int dequeue(){
        //If head==tail, the queue is empty
        if(head==tail) return -1;//Here - 1 indicates that the queue is empty
        int ret=items[head];
        ++head;
        return ret;
    }

    //Print queue
    public void PrintQueue(){
        for(int i=head;i<tail;++i){
            System.out.print(items[i]+" ");
        }
        System.out.println();
    }

}

2. Queue based on linked list

  • Constructor
  • Entry operation
  • Out of line operation
  • Print elements in queue
package Queue;

//Queue based on linked list
public class LinkedListQueue {

    private Node head;//Link to the first node added
    private Node tail;//Links to recently added nodes
    private int N;//Number of elements in the queue
    private class Node{
        //The nested classes of nodes are defined
        int data;
        Node Next;
    }
    public boolean isEmpty(){
        return head==null;
    }
    public int size(){ return N;}

    //Add elements to the end of the table to join the team
    public void enqueue(int data){
        Node newNode=tail;
        tail=new Node();
        tail.data=data;
        tail.Next=null;
        if(isEmpty()) head=tail;
        else newNode.Next=tail;
        ++N;
    }
    public int dequeue(){
        //Remove element from header
        int data=head.data;
        head=head.Next;
        if(isEmpty()) tail=null;
        N--;
        return data;
    }

    //Printout queue elements
    public void PrintQueue(){
        for(Node x=head;x!=null;x=x.Next){
            System.out.print(x.data+" ");
        }
        System.out.println();
    }
}

3. Loop queue based on array

  • Constructor
  • Entry operation
  • Out of line operation
  • Print elements in queue
package Queue;

public class CircularQueue {
    //Array items, array size n
    private int[] items;
    private int n=0;
    //Head is the team's head and tail is the team's tail
    private int head=0;
    private int tail=0;

    //Request an array of size capacity
    public CircularQueue(int capacity){
        items = new int[capacity];
        n=capacity;
    }

    //Join the team
    public boolean enqueue(int item){
        //The queue is full
        if((tail+1)%n==head) return false;
        items[tail]=item;
        tail=(tail+1)%n;//Loop for counting
        return true;
    }

    //Out of the team
    public int dequeue(){
        //If head==tail, the queue is empty
        if(head==tail) return -1;//Empty queue with - 1
        int ret=items[head];
        head=(head+1)%n;
        return ret;
    }

    //Print queue
    public void PrintQueue(){
        if(n==0) return;
        for(int i=head;i%n!=tail;i=(i+1)%n){
            System.out.print(items[i]+" ");
        }
        System.out.println();
    }
}

explain

There are too many article codes. I originally wanted to write them in several articles, but for some reasons, they were put together, which is a little bloated. The code has been tested by test cases, and there should be no errors.

If the experience is not good, you can move my Github , it looks good inside.

Extras: for beginners of algorithm, we recommend a very nice book algorithm fourth edition, which has a variety of detailed drawings. If you need an electronic file, the background reply algorithm 4 can get the download link. Background reply algorithm 01 will send you a mind map of algorithm and data structure. Finally, I hope we can make progress and grow together!

Tags: Java github C

Posted on Sat, 27 Jun 2020 00:08:28 -0400 by bache