1 - queue, linked list, stack

1. Logical structure and physical structure (storage structure)

1.1 logical structure

  • Set structure (unrelated)
  • Linear structure (one to one)
    • Representative: linear table, stack, queue, string
  • Nonlinear structure
    • Tree structure (one to many)
    • Graphic structure (many to many)

1.2 physical structure

  • Sequential storage structure
  • Linked Storage Structure
  • Indexes
  • Hash table

2. Sparse array

2.1 introduction

  • When there are few valid values and many zeros in an array, it can be stored in a sparse array. SparseArray
  • As shown below, row 0 of the sparse array, the first column 6 indicates how many rows the original array has, the second column 7 indicates how many columns the original array has, and the third column 8 indicates how many non-0 elements the original array has. The row and column of the non-0 element of the records from row 1 to the last row of the sparse array and its value.
  • Thus, the column of the sparse array must be 3, and the number of rows is the number of non-0 elements of the original array + 1 (row 0).

2.2 code implementation

package SparseArray;

public class Demo01 {

    public static void main(String[] args) {
        // 1. Create the original array. As long as the required place is assigned a value other than 0, the rest will be 0 by default
        int[][] o_array = new int[5][6];
        o_array[1][3] = 1;
        o_array[2][4] = 2;
        o_array[0][3] = 5;
        o_array[3][2] = 4;
        // 2. Get the rows and columns of the original array
        int lenx = o_array.length;
        int leny = o_array[0].length;

        // 3. Get the number of non-0 elements
        int non_zero = 0;
        for (int i =0; i<lenx;i++){
            for (int j=0;j<leny;j++){
                int temp = o_array[i][j];
                if(temp!=0){
                    non_zero++;
                }
            }
        }

        // 4. Create a sparse array
        int[][] sparse_array = new int[non_zero+1][3];
        sparse_array[0][0] = lenx;
        sparse_array[0][1] = leny;
        sparse_array[0][2] = non_zero;

        // 5. Traverse the original array and fill the non-0 elements into the sparse array
        int x = 1;
        for (int i =0; i<lenx;i++){
            for (int j=0;j<leny;j++){
                int temp = o_array[i][j];
                if(temp!=0){
                    sparse_array[x][0] = i;
                    sparse_array[x][1] = j;
                    sparse_array[x][2] = temp;
                    x++;
                }
            }
        }

        // 6. Output original array
        System.out.println("The original array is as follows");
        for (int[] row: o_array){
            for (int data:row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        // 7. Output sparse array
        System.out.println("The sparse array is as follows");
        for (int[] row:sparse_array){
            for (int data:row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }

        // 8. Restore the sparse array to the original array
        // 8.1 first obtain the data in the first row of the sparse array to create the original array size
        int lenx2 = sparse_array[0][0];
        int leny2 = sparse_array[0][1];
        int[][] array2 = new int[lenx2][leny2];

        // 8.2 traverse the sparse array, starting from line 2. Restore data
        for (int i=1; i< sparse_array.length; i++){
            array2[ sparse_array[i][0] ][ sparse_array[i][1] ] = sparse_array[i][2];
        }

        // 8.3 output new restored original array
        System.out.println("The restored original array is as follows");
        for (int[] row: array2){
            for (int data:row){
                System.out.printf("%d\t", data);
            }
            System.out.println();
        }
    }
}

3 queue

3.1 introduction

  • Queue is an ordered list, which can be implemented by array or linked list
  • First in first out

3.2 code implementation

  • The default value of rear and front is - 1 (when adding and fetching data, first + 1 and then add). If the default value is 0, the operation process is different (when adding, first add, then rear+1, when fetching data, first fetch and then front+1).

  • The following queue is one-time. After the queue is filled with values, it can no longer be added, because the filled values do not leave the queue, but only return values.

public class Demo {
    public static void main(String[] args) {

        ArrayQueue a = new ArrayQueue(5);
        a.addQueue(1);
        a.addQueue(2);
        a.addQueue(3);
        a.addQueue(4);
        a.addQueue(5);
        a.showAllQueue();
        System.out.println();
        System.out.println(a.getQueue());
        System.out.println(a.getQueue());
        System.out.println(a.getQueue());
        System.out.println();
        a.showAllQueue();
        System.out.println();
        a.showQueue();
        a.addQueue(6);
        a.addQueue(7);
        a.addQueue(8);
        a.showAllQueue();

    }
}


class ArrayQueue{
    private int maxSize;    // Maximum queue capacity
    private int front;      // Queue header pointer
    private int rear;       // End of queue pointer
    private int[] arr;      // Array, used to simulate the queue and save data

    // constructor 
    public ArrayQueue(int maxSize){
        this.maxSize = maxSize;
        arr = new int[maxSize];
        front = -1;
        rear = -1;
    }

    // Judge whether the queue is full. If the tail pointer = = maximum value - 1 (starting with tail pointer 0), it indicates that it is full
    public boolean isFull(){
        return rear==maxSize-1;
    }

    // Judge whether the queue is empty. If the head and tail pointers are the same, it is empty
    public boolean isEmpty(){
        return front==rear;
    }

    // Add data to queue
    public void addQueue(int n){
        if (isFull()) {
            System.out.println("The queue is full and data cannot be added!");
            return;
        }
        // arr[++rear] = n;
        // perhaps
        rear ++;
        arr[rear] = n;
    }

    // Get queue data, that is, take out data from the header
    public int getQueue(){
        if(isEmpty()){
            // You cannot return because the value of return may be the value of a queue element
            throw new RuntimeException("The queue is empty and data cannot be retrieved");
        }
        front++;
        return arr[front];
    }

    // Print the contents not taken out of the queue
    public void showQueue(){
        if (isEmpty()){
            System.out.println("The queue is empty and there is no data");
            return;
        }
        for (int i=front+1; i<arr.length; i++){
            System.out.printf("arr[%d] == %d\t", i, arr[i]);
        }
    }

    // Print all the contents of the queue. Even if there is extracted data, it is only returned, but it is not deleted in arr!
    public void showAllQueue(){
        if (isEmpty()){
            System.out.println("The queue is empty and there is no data");
            return;
        }
        for (int i=0; i<arr.length; i++){
            System.out.printf("arr[%d] == %d\t", i, arr[i]);
        }
    }

    // Get header data
    public int getHead(){
        if (isEmpty()) throw new RuntimeException("The queue is empty, unable to get header data");
        return arr[++front];
    }
}

4 ring queue

4.1 introduction

  • Because the queue in 3 is one-time, a ring queue is constructed so that the queue can be reused!
  • Refer to p114-p117 (very important) of Dahua data structure for details of ring queue
  • The reason why rear points to an empty space is to distinguish whether rear == front is empty or full! When rear == front, it is empty, and (the index of the empty space pointed to by rear + 1)% maxSize, if = = front, it is full

4.2 code implementation

package MyQueue;

public class CircleQueue {

    private int maxSize;    // Maximum queue capacity
    private int front;      // Queue header pointer, default 0
    private int rear;       // Points to the next position of the last element of the queue, and the position can only be empty. The default is 0
    private int[] arr;      // Array, used to simulate the queue and save data

    // constructor 
    public CircleQueue(int maxSize1){
        this.maxSize = maxSize1+1;
        arr = new int[maxSize];
        front = 0;
        rear = 0;
    }

    // Judge whether the queue is full. If the tail pointer = = maximum value - 1 (starting with tail pointer 0), it indicates that it is full
    public boolean isFull(){
        return (rear+1)%maxSize == front;
    }

    // Judge whether the queue is empty. If the head and tail pointers are the same, it is empty
    public boolean isEmpty(){
        return front==rear;
    }

    // Add data to queue
    public void addQueue(int n){
        if (isFull()) {
            System.out.println("The queue is full and data cannot be added!");
            return;
        }
        arr[rear] = n;
        rear = (rear+1)%maxSize;
    }

    // Get queue data, that is, take out data from the header
    public int getQueue(){
        if(isEmpty()){
            // You cannot return because the value of return may be the value of a queue element
            throw new RuntimeException("The queue is empty and data cannot be retrieved");
        }
        int res = arr[front];
        front = (front+1)%maxSize;
        return res;
    }

    // Print all the contents of the queue. Even if there is extracted data, it is only returned, but it is not deleted in arr!
    public void showAllQueue(){
        if (isEmpty()){
            System.out.println("The queue is empty and there is no data");
            return;
        }
        for (int i=front; i<front+getSize(); i++){
            System.out.printf("arr[%d] == %d\t", i%maxSize, arr[i%maxSize]);
        }
    }

    // Get queue length
    public int getSize(){
        return (rear - front + maxSize)%maxSize;
    }

    // Get header data
    public int getHead(){
        if (isEmpty()) throw new RuntimeException("The queue is empty, unable to get header data");
        return arr[front];  // front directly points to the first element. After returning, it does not need + +, and the queue needs + +;
    }
}



5 linked list

5.1 refer to big talk data structure

5.2 single linked list

5.2.1 code example of single linked list directly inserted into tail node

package LinkedList;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        Node n1 = new Node(1,1);
        Node n2 = new Node(2,2);
        Node n3 = new Node(3,3);
        SingleLinkedList s1 = new SingleLinkedList();
        s1.addNode(n1);
        s1.addNode(n2);
        s1.addNode(n3);
        s1.list();
        // out message
        // Node{num=1, data=1}
        // Node{num=2, data=2}
        // Node{num=3, data=3}
    }
}

class SingleLinkedList {
    // The head node cannot be moved
    private Node head = new Node(0, 0);

    // Add a new node
    public void addNode(Node n){
        // temp gets the temporary node and starts traversal
        Node temp = head;

        // Find the last node and add the new node directly
        while (true){
            // If the current node next=null, it means that it is currently the tail node, and the loop will jump out
            if (temp.next == null){
                break;
            }
            // Otherwise, look at the next node
            temp = temp.next;
        }
        // Add node
        temp.next = n;
    }

    // Display linked list
    public void list(){
        // first to assert isEmpty
        if (head.next == null){
            System.out.println("the list is empty!");
            return;
        }
        // head node we can not use, so make temp = head node.
        // because if head node is used, it will point other value
        Node temp = head.next;
        // Judge whether the last node is empty. If it is empty, it means that the current node is the last node, and the cycle is directly pushed out.
        // If it is not empty, the node information is output and the next node is judged.
        while (true){
            if (temp == null){
                break;
            }
            System.out.println(temp);
            temp = temp.next;
        }

    }
}

class Node{
    public int num;     // Default 0
    public int data;    // Default 0
    public Node next;   // Default null

    public Node(int num, int data){
        this.num = num;
        this.data = data;
    }

	// There is no + next, otherwise it will be a doll
    @Override
    public String toString() {
        return "Node{" +
                "num=" + num +
                ", data=" + data +
                '}';
    }
}

5.2.2 code implementation of single linked list with sorting

  • Sort and insert nodes according to num, from small to large
  • First find the insertion location, temp node, which must be the previous node of the insertion location.
  • Just add an addbynum method.
 
	 // Sort from small to large according to node num
    public void addNodeSortByNum(Node n){
        // The head node cannot be modified, so temp == head is used
        // The head node should be in the previous position of the inserted node, otherwise it cannot be inserted
        // The previous node cannot be found because there is no precursor pointer
        Node temp = head;
        boolean flag = false;   // If the added number num exists, it becomes true
        // Find the location node temp we need to insert. This node is the previous node of the newly inserted node
        while (true){
            if (temp.next == null){
                // If temp.next == null, it means that this temp is the tail node and the node we are looking for
                break;
            }
            if (temp.next.num > n.num){
                // If the node num after temp > insert node num, it means that it should be inserted in
                // Between temp node and temp.next node
                // At this time, temp is the node we are looking for
                break;
            }
            else if (temp.next.num==n.num){
                // The added number already exists
                flag = true;
                break;
            }
            temp = temp.next;   // If not found, judge the next node
        }

        if (flag){
            System.out.println("The inserted number already exists, The number is: "+ n.num);
        }
        else{
            // Insert into the linked list, after temo
            n.next = temp.next;
            temp.next = n;
        }
    }

5.2.3 modify nodes and delete nodes

 public void updateNodeByNum(Node n){
        if (head.next==null){
            System.out.println("The linked list is empty!");
            return;
        }
        // Find the node to modify
        Node temp = head.next;
        boolean flag = false;   // true means found

        while (true){
            if (temp == null){
                break;  // The traversal is over. If you can't find it, just exit
            }
            if (temp.num == n.num){
                // eureka
                flag = true;
                break;
            }
            temp = temp.next;
        }

        if (flag){
            // Found. Modify the data of the node
            temp.data = n.data;
        }
        else {
            // Can't find
            System.out.printf("Node number not found%d The node cannot be modified\n", n.num);
        }
    }
  • Deleting a node is a single linked list, so if we want to delete the node indicated by the red arrow, we must find its previous node (indicated by green). Otherwise, the previous node of the deleted node cannot be connected to the next node of the deleted node, and a new linked list cannot be formed.
  • Once found, temp.next = temp.next.next.
  • If the deleted node has no reference, it will be recycled by GC.
public void deleteNodeByNum(int num){
        // Determine whether the linked list is empty
        if (head.next == null){
            System.out.println("The linked list is empty");
            return;
        }

        Node temp = head;
        boolean flag = false;
        while (true){
            if (temp.next.num == num){
                // eureka
                flag = true;
                break;
            }
            if (temp.next == null){
                // Traversal ended, not found
                break;
            }
            temp = temp.next;   // No, move back
        }
        if (flag){
            temp.next = temp.next.next;
            System.out.println("Delete complete");
        }
        else {
            System.out.println("The node was not found, deletion failed");
        }
    }

5.2.5 bidirectional linked list

5.2.6 circular linked list

  • There is a one-way circular linked list and a two-way circular linked list
  • Solving Joseph's problem with one-way circular linked list
  • We use the tail pointer instead of the head pointer, because the head pointer finds the head node is O(1) and the tail node is O(n). Therefore, let the rear node point to the prior ity node (i.e. the last node) of the head node. At this time, the header is rear.next, the first node (the node behind the head node) is rear.next.next, and the tail node is its own O1.
  • How to judge if the circular linked list is Full, temp. Next= Head is not Full
  • Determine whether it is empty or temp.next == null

6 stacks

6.1 application scenarios

6.2 code representation

package MyStack;

public class demo {
    public static void main(String[] args) {
        MyStack m1 = new MyStack(10);
        m1.push(1);
        m1.push(2);
        m1.push(3);
        m1.push(4);
        m1.push(5);
        m1.push(6);
        m1.push(7);
        m1.push(8);
        m1.push(9);
        m1.push(10);
        m1.list();
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
        System.out.println(m1.pop());
    }
}


class MyStack{
    private int maxSize;    // The size of the stack. The index should be - 1, so top < = maxsize-1
    private int top = -1;   // Top stack top
    private int[] stack;    // Array simulation stack

    public MyStack(int maxSize){
        this.maxSize = maxSize;
        stack = new int[this.maxSize];
    }

    // Determine whether the stack is full
    public boolean isFull(){
        return top == maxSize-1;
    }

    // Judge stack empty
    public boolean isEmpty(){
        return top == -1;
    }

    // Push 
    public void push(int value){
        if (isFull()){
            System.out.println("stack is full");
            return;
        }
        stack[++top] = value;
    }

    // Out of stack
    public int pop(){
        if (isEmpty()){
            throw new RuntimeException("stack is empty");
        }
        return stack[top--];
    }

    // Traverse the stack and display data from the top of the stack
    public void list(){
        if (isEmpty()){
            System.out.println("stack is empty");
            return;
        }
        // The following method does not work. Because the top value is modified, you need to replace top with temp
        // while ( !(top<0) ){
        //     System.out.println(stack[top--]);
        // }
        int temp = top;
        while ( !(temp<0) ){
            System.out.println("stack[" + temp + "] = " + stack[temp]);
            temp--;
        }

        // Video method
        // for (int i=top; i>=0;i--){
        //     System.out.printf("stack[%d] = %d\n", i, stack[i]);
        // }
    }
}

6.3 four operation cases


https://www.bilibili.com/video/BV1E4411H73v?p=33&spm_id_from=pageDriver


Tags: data structure

Posted on Mon, 01 Nov 2021 01:52:56 -0400 by snoopy13