Data structure - linear table

Posted by The Jackel on Fri, 28 Jan 2022 12:00:16 +0100

3, Linear table

Linear table is the most basic, simplest and most commonly used data structure. A linear table is a finite sequence of n data elements with the same characteristics.

Precursor element:

If element A is in front of element B, it is called the precursor element of B

Successor elements:

If element B follows element a, it is called the successor element of A

**Features of linear table: * * there is a "one-to-one" logical relationship between data elements.

  1. The first data element has no precursor, and this data element is called the header node;

  2. The last data element has no successor, and this data element is called the tail node;

  3. Except for the first and last data elements, other data elements have and have only one precursor and one successor.

If the linear table is defined in mathematical language, it can be expressed as (a1,... ai-1,ai,ai+1,... an). ai-1 is ahead of ai,ai is ahead of ai+1, and ai-1 is called ai

The precursor element, ai+1, is the successor element of ai

Classification of linear table:

The data storage mode in the linear table can be sequential storage or chain storage. According to different data storage modes, the linear table can be divided into sequential storage

Lists and linked lists.

1.1 sequence table

Sequential table is a linear table saved in the form of array in computer memory. Sequential storage of linear table refers to sequential storage with a group of storage units with continuous addresses

Each element in the linear table is stored so that the data elements that ring logically in the linear table are stored in adjacent physical storage units, that is, through data elements

The adjacency relationship between data elements is reflected by the adjacency relationship of physical storage.

1.1.1 implementation of sequence table

Code implementation of sequence table:

public class SequenceList<T> implements Iterable {

    // An array of storage elements
    private T[] eles;
    // Length of current linear table
    private int N;

    /*
        Create a SequenceList object with capacity
     */
    public SequenceList(int capacity) {
        // Initialize array
        this.eles = (T[]) new Object[capacity];
        // Initialization length
        this.N = 0;
    }

    /*
        Vacant linear table
     */
    public void clear() {
        this.N = 0;
    }

    /*
        Judge whether the linear table is empty, return true if yes, and return false if No
     */
    public boolean isEmpty() {
        return N == 0;
    }


    /*
      Length of linear table
    */
    public int length() {
        return N;
    }

    /*
       Reads and returns the value of the ith element in the linear table
     */
    public T get(int i) {
        return eles[i];
    }

    /*
        Add an element t to the linear table
     */
    public void insert(T t) {
        if (N == eles.length) {
            resize(2 * eles.length);
        }
        eles[N++] = t;
    }

    /*
       Insert a data element with a value of t before the ith element of the linear table.
     */
    public void insertBefore(int i, T t) {
        if (N == eles.length) {
            resize(2 * eles.length);
        }

        // First, move the index element and its subsequent elements backward by one bit
        for (int index = N; index > i; index--) {
            eles[index] = eles[index - 1];
        }
        // Then put the t element at the i index
        eles[i] = t;
        // Number of elements plus 1
        N++;
    }


    /*
        Delete and return the ith data element in the linear table.
     */
    public T remove(int i) {
        // Record the value at index i
        T current = eles[i];
        // The elements after index i move forward one bit in turn
        for (int index = i; index < N - 1; index++) {
            eles[index] = eles[index + 1];
        }
        N--;
        if (N < eles.length / 4) {
            resize(eles.length / 2);
        }

        return current;
    }

    /*
        Returns the bit sequence number of the specified data element that appears for the first time in the linear table. If it does not exist, it returns - 1.
     */
    public int indexOf(T t) {
        for (int i = 0; i < N; i++) {
            if (eles[i].equals(t)) {
                return i;
            }
        }
        return -1;
    }

    // Reset the size of eles according to the parameter newSize
    public void resize(int newSize) {
        // Define a temporary array that points to the original array
        T[] temp = eles;
        // Create a new array
        eles = (T[]) new Object[newSize];
        // Copy the data of the original array to the new array
        for (int i = 0; i < N; i++) {
            eles[i] = temp[i];
        }
    }


    public Iterator<T> iterator() {
        return new SIterator();
    }

    private class SIterator implements Iterator {

        private int cusor;

        public SIterator() {
            this.cusor = 0;
        }

        public boolean hasNext() {
            return cusor < N;
        }

        public Object next() {
            return eles[cusor++];
        }

        public void remove() {

        }
    }
}

1.1.2 traversal of sequence table

Generally, when storing data as a container, we need to provide traversal mode to the outside, so we need to provide traversal mode to the sequence table.

In java, foreach loops are generally used to traverse collections. If we want our SequenceList to support foreach loops,

You need to do the following:

  1. Let SequenceList implement Iterable interface and rewrite iterator method;

  2. Provide an internal class SIterator inside the SequenceList, implement the Iterator interface, and rewrite hasNext method and next method;

Code reference above

1.1.3 variable capacity of sequence table

In the previous implementation, when we use SequenceList, we first create an object with new SequenceList(5). When creating an object, we need to specify the content

Initializes an array of the specified size to store elements. When we insert elements, if five elements have been inserted, we will continue to insert the number of elements

According to the data, it will report an error and cannot be inserted. This design does not conform to the design concept of the container, so we should consider its capacity when designing the sequence table

Scalability.

Considering the capacity scalability of the container is actually changing the size of the array storing data elements. We need to consider when we need to change the size of the array

Small?

  1. When adding elements:

When adding elements, you should check whether the size of the current array can accommodate new elements. If not, you need to create a new array with larger capacity. I

Here we create a new array storage element with twice the capacity of the original array.

  1. When removing an element:

When removing elements, you should check whether the size of the current array is too large. For example, you are using an array with 100 capacity to store 10 elements, which will cause memory loss

To waste space, you should create a smaller array storage element. If we find that the number of data elements is less than 1 / 4 of the capacity of the array, we create

One is a new array storage element that is 1 / 2 of the capacity of the original array.

1.1.4 time complexity of sequence table

get(i): it is not difficult to see that no matter how large the number of data elements N is, the corresponding elements can be obtained only once eles[i], so the time complexity is O(1);

Insert (int i, t, t): every time you insert, you need to move the element behind the I position once. As the number of elements N increases, more elements will be moved

The inter complex is O(n);

remove(int i): every time you delete, you need to move the element behind position I once. With the increase of the amount of data N, more elements will be moved, and the time will be longer

The impurity is O(n);

Since the bottom layer of the sequence table is realized by the array, and the length of the array is fixed, the container expansion operation is involved in the process of operation. This will lead to a smooth flow

The time complexity of the sequence table in the use process is not linear. At some nodes that need to be expanded, the time will increase sharply, especially with more elements

The more obvious

1.1.5 implementation of ArrayList in Java

The bottom layer of ArrayList set in java is also a sequence table, which is implemented by array. It also provides functions such as addition, deletion, modification, query and capacity expansion.

1.2 linked list

We have implemented the linear table using the sequential storage structure before. We will find that although the query of the sequential table is very fast and the time complexity is O(1), it can be added or deleted

The efficiency of is relatively low, because each addition and deletion operation is accompanied by the movement of a large number of data elements. Is there a solution to this problem? Yes, we can

To use another storage structure to realize linear list and chain storage structure.

Linked list is a non continuous and non sequential storage structure on the physical storage unit. Its physical structure can not only represent the logical order of data elements

The logical order of elements is realized through the pointer link order in the linked list. The linked list consists of a series of nodes (each element in the linked list is called a node),

Nodes can be generated dynamically at runtime.

How do we use the linked list? According to the object-oriented idea, we can design a class to describe the node and use an attribute to describe the node

The element stored in the node is used to describe the next node of this node with another attribute.

Node API design:

Node class implementation:

   public class Node {
        //Storage element
        public T item;
        // Point to the next node
        public Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }

Generate linked list:

   public static void main(String[] args) throws Exception {
        //Build node
        Node<Integer> first = new Node<Integer>(11, null);
        Node<Integer> second = new Node<Integer>(13, null);
        Node<Integer> third = new Node<Integer>(12, null);
        Node<Integer> fourth = new Node<Integer>(8, null);
        Node<Integer> fifth = new Node<Integer>(9, null);
        //Generate linked list
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
    }

1.2.1 one way linked list

Unidirectional linked list is a kind of linked list. It is composed of multiple nodes. Each node is composed of a data field and a pointer field. The data field is used to store data,

The pointer field is used to point to its successor node. The data field of the head node of the linked list does not store data, and the pointer field points to the first node that actually stores data.

1.2.1.1 API design of one-way linked list

1.2.1.2 one way linked list code implementation

public class LinkList<T> implements Iterable {

    // Record first node
    private Node head;
    // Length of the current linked list
    private int N;

    /*
        Create a SequenceList object with capacity
     */
    public LinkList() {
        // Initialize header node
        this.head = new Node(null, null);
        // Number of initialization elements
        this.N = 0;
    }

    /*
        Vacant linear table
     */
    public void clear() {
        this.head.next = null;
        this.N = 0;
    }

    /*
        Judge whether the linear table is empty, return true if yes, and return false if No
     */
    public boolean isEmpty() {
        return this.N == 0;
    }


    /*
      Length of linear table
    */
    public int length() {
        return this.N;
    }

    /*
       Reads and returns the value of the ith element in the linear table
     */
    public T get(int i) {
        // Through the loop, start from the node and look back
        Node n = this.head.next;
        for (int index = 0; index < i; index++) {
            n = n.next;
        }
        return n.item;
    }

    /*
        Add an element t to the linear table
     */
    public void insert(T t) {
        // Find the last current node
        Node n = head;
        while (n.next != null) {
            n = n.next;
        }
        // Create a new node and save the element t
        Node newNode = new Node(t, null);
        // Make the current last node point to the new node
        n.next = newNode;
        // Number of elements + 1
        N++;
    }

    /*
       Insert a data element with a value of t before the ith element of the linear table.
     */
    public void insertBefore(int i, T t) {
        // Find the previous node at position i
        Node pre = head;
        for (int index = 0; index < i; index++) {
            pre = pre.next;
        }
        // Find the node at position i
        Node curr = pre.next;
        // To create a new node, bin gives money. The new node needs to point to the node at the original i location
        Node newNode = new Node(t, curr);
        // The previous node in the original i position can point to the new node
        pre.next = newNode;
        // Number of elements + 1
        N++;
    }

    /*
        Delete and return the ith data element in the linear table.
     */
    public T remove(int i) {
        // Find the previous node at position i
        Node pre = head;
        for (int index = 0; index < i; index++) {
            pre = pre.next;
        }
        // Find the node at position i
        Node curr = pre.next;
        // Find the next node at position i
        Node nextNode = curr.next;
        // The previous node points to the next node
        pre.next = nextNode;
        //Number of elements - 1
        N--;
        return curr.item;
    }

    /*
        Returns the bit sequence number of the specified data element that appears for the first time in the linear table. If it does not exist, it returns - 1.
     */
    public int indexOf(T t) {
        // Start from the beginning. Then find each node, take out item and t, and compare them: if they are the same, they are found
        Node n = head;
        for (int i = 0; n.next != null; i++) {
            n = n.next;
            if (n.item.equals("t")) {
                return i;
            }
        }
        return -1;
    }

    public Iterator<T> iterator() {
        return new SIterator();
    }

    private class SIterator implements Iterator {

        private Node n;

        public SIterator() {
            this.n = head;
        }

        public boolean hasNext() {
            return n.next != null;
        }

        public Object next() {
            n = n.next;
            return n.item;
        }

        public void remove() {

        }
    }

    public class Node {
        //Storage element
        public T item;
        // Point to the next node
        public Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
}
public class LinkListTest {
    public static void main(String[] args) {
        // Create a one-way linked list object
        LinkList<String> sl = new LinkList<String>();
        // Test insertion
        sl.insert("Yao Ming");
        sl.insert("Kobe");
        sl.insert("McGrady");
        sl.insertBefore(2, "James");
        for (Object s : sl) {
            System.out.println((String) s);
        }
        System.out.println("-----------------------");


        // Test acquisition
        String getResult = sl.get(0);
        System.out.println("The value at get index 0 is:" + getResult);
        String getResult2 = sl.get(sl.length()-1);
        System.out.println("Get the value of the index as:" + getResult2);
        // Test delete
        String removeResult = sl.remove(0);
        System.out.println("Get the value where index 0 is deleted is:" + removeResult);
        // Test empty
        sl.clear();
        System.out.println("The number of elements in the cleared linear table is:" + sl.length());
    }
Output:
Yao Ming
 Kobe
 James
 McGrady
-----------------------
The value at get index 0 is: 0
 Get the value of the index: McGrady
 Get the deleted value of index 0: 0
 The number of elements in the cleared linear table is: 0

1.2.2 bidirectional linked list

Bidirectional linked list, also known as bidirectional list, is a kind of linked list. It is composed of multiple nodes. Each node is composed of a data field and two pointer fields

To store data, one pointer field is used to point to its successor node, and the other pointer field is used to point to the precursor node. The data field of the head node of the linked list does not exist

For storing data, the value of the pointer field pointing to the predecessor node is null, and the pointer field pointing to the successor node points to the first node that actually stores data.

According to the object-oriented idea, we need to design a class to describe the node. Because the node belongs to the linked list, we make the node class

It is implemented as an internal class of the linked list class

1.2.2.1 node API design

1.2.2.2 API design of bidirectional linked list

1.2.2.3 code implementation of bidirectional linked list

public class TowWayLinkList<T> implements Iterable {

    // Record first node
    private Node head;
    // Record tail node
    private Node last;
    // Length of the current linked list
    private int N;

    /*
        Create a SequenceList object with capacity
     */
    public TowWayLinkList() {
        // Initialize header node
        this.head = new Node(null, null, null);
        // Initialize tail node
        this.last = null;
        // Number of initialization elements
        this.N = 0;
    }

    /*
        Vacant linear table
     */
    public void clear() {
        this.head.next = null;
        this.head.pre = null;
        this.head.item = null;
        this.last = null;
        this.N = 0;
    }

    /*
        Judge whether the linear table is empty, return true if yes, and return false if No
     */
    public boolean isEmpty() {
        return N == 0;
    }


    /*
      Length of linear table
    */
    public int length() {
        return N;
    }

    /*
         Get the first element
      */
    public T getFirst() {
        if (isEmpty()) {
            return null;
        }
        return head.next.item;
    }

    /*
        Get the last element
     */
    public T getLast() {
        if (isEmpty()) {
            return null;
        }
        return last.item;
    }

    /*
       Reads and returns the value of the ith element in the linear table
     */
    public T get(int i) {
        Node n = head.next;
        for (int index = 0; index < i; index++) {
            n = n.next;
        }

        return n.item;
    }

    /*
        Add an element t to the linear table
     */
    public void insert(T t) {
        // If the linked list is empty
        if (isEmpty()) {
            // Create a new node
            Node newNode = new Node(t, head, null);
            // Let the new node be called the tail node
            last = newNode;
            // Let the head node point to the tail node
            head.next = last;
        } else {
            // Linked list is not empty
            Node oldLast = last;
            // Create a new node
            Node newNode = new Node(t, oldLast, null);
            // The current tail node points to the new node
            oldLast.next = newNode;
            // Let the new node be called the tail node
            last = newNode;
        }
        N++;
    }

    /*
       Insert a data element with a value of t before the ith element of the linear table.
     */
    public void insertBefore(int i, T t) {
        // Find the previous node at position i
        Node pre = head;
        for (int idnex = 0; idnex < i; idnex++) {
            pre = pre.next;
        }
        // Find the node at position i
        Node INode = pre.next;
        // Create a new node
        Node newNode = new Node(t, pre, INode);
        //Make the next node of the previous node at i position become a new node
        pre.next = newNode;
        // Make the previous node at i position become a new node
        INode.pre = newNode;
        // Number of elements + 1
        N++;

    }

    /*
        Delete and return the ith data element in the linear table.
     */
    public T remove(int i) {
        // Find the previous node of i position
        Node pre = head;
        for (int index = 0; index < i; index++) {
            pre = pre.next;
        }
        // Find the node at i location
        Node curr = pre.next;
        // Find the next node at position i
        Node nextNode = curr.next;
        // Let the next node of the previous node of i position become the next node of i position
        pre.next = nextNode;
        // Let the previous node of the next node in position I become the previous node in position i
        nextNode.pre = pre;
        // Number of elements - 1
        N--;
        return curr.item;
    }

    /*
        Returns the bit sequence number of the specified data element that appears for the first time in the linear table. If it does not exist, it returns - 1.
     */
    public int indexOf(T t) {
        Node n = head;
        for (int i = 0; n.next != null; i++) {
            n = n.next;
            if (n.next.equals(t)) {
                return i;
            }
        }
        return -1;
    }


    public Iterator<T> iterator() {
        return new SIterator();
    }

    private class SIterator implements Iterator {

        private Node n;

        public SIterator() {
            this.n = head;
        }

        public boolean hasNext() {
            return n.next != null;
        }

        public Object next() {
            n = n.next;
            return n.item;
        }

        public void remove() {

        }
    }

    public class Node {
        //Storage element
        public T item;
        // Point to the next node
        public Node next;
        // Point to previous node
        public Node pre;

        public Node(T item, Node pre, Node next) {
            this.item = item;
            this.next = next;
            this.pre = pre;
        }
    }
}

public class TowWayLinkListTest {
    public static void main(String[] args) {
        // Create a two-way linked list object
        TowWayLinkList<String> sl = new TowWayLinkList<String>();
        // Test insertion
        sl.insert("Yao Ming");
        sl.insert("Kobe");
        sl.insert("McGrady");
        sl.insertBefore(2, "James");
        for (Object s : sl) {
            System.out.println((String) s);
        }
        System.out.println("-----------------------");


        // Test acquisition
        String getResult = sl.get(0);
        System.out.println("The value at get index 0 is:" + getResult);
        String getResult2 = sl.get(sl.length()-1);
        System.out.println("Get the value of the index as:" + getResult2);
        // Test delete
        String removeResult = sl.remove(0);
        System.out.println("Get the value where index 0 is deleted is:" + removeResult);
        // Test empty
//        sl.clear();
//        System.out.println("the number of elements in the cleared linear table is:" + sl.length());

        System.out.println("----------------------------");
        System.out.println("First element"+sl.getFirst());
        System.out.println("Last element"+sl.getLast());

    }
}
Output:
Yao Ming
 Kobe
 James
 McGrady
-----------------------
The value at get index 0 is: 0
 Get the value of the index: McGrady
 Get the deleted value of index 0: 0
----------------------------
The first element is Kobe
 The last element is McGrady

1.2.2.4 implementation of LinkedList in Java

The LinkedList set in java is also implemented by using a two-way linked list, and provides related methods such as addition, deletion, modification and query

1.2.3 complexity analysis of linked list

get(int i): for each query, you need to start from the head of the linked list and search backward in turn. With the increase of data element N, the more elements to compare, and the longer the query time

Complexity is O(n)

Insert (int i, t, t): for each insertion, you need to find the previous element at position I first, and then complete the insertion operation. As the number of data elements N increases, the number of search elements increases

The more elements, the time complexity is O(n);

remove(int i): for each removal, you need to find the previous element in position I first, and then complete the insertion operation. As the number of data elements N increases, the number of search elements increases

The more elements, the time complexity is O(n)

Compared with the sequential list, the insertion and deletion time complexity of the linked list is the same, but it still has great advantages because the physical addresses of the linked list are discontinuous,

It does not need to specify the size of storage space in advance, or involve operations such as capacity expansion in the storage process, and it does not involve the exchange of elements.

Compared with sequential list, the query performance of linked list will be lower. Therefore, if there are many query operations in our program, it is recommended to use the sequence table to add or delete

There are many operations. It is recommended to use linked list.

1.2.4 linked list inversion

The reversal of single linked list is a high-frequency topic in the interview.

Requirements:

The data in the original linked list is: 1 - > 2 - > 3 > 4

After inversion, the data in the linked list is: 4 - > 3 - > 2 - > 1

Reverse API:

public void reverse(): reverse the entire linked list

public Node reverse(Node curr): reverses a node curr in the linked list and returns the reversed curr node

Recursion can be used to complete inversion. Recursive inversion actually starts from the first node of the original linked list to store data, and recursively calls and reverses each node in turn,

Until the last node is reversed, the whole linked list is reversed.

    /*
     Reverse the entire linked list
     */
    public void reverse() {
        // Judge whether the current linked list is an empty linked list. If it is an empty linked list, end the operation. If not, call the overloaded reverse method to complete the inversion
        if (isEmpty()) {
            return;
        }
        reverse(head.next);
    }

    /*
        Invert the specified curr node in the linked list and return the inverted curr node
        Original order
        Yao Ming
        Kobe
        James
        McGrady
     */
    public Node reverse(Node curr) {
        if (curr.next == null) {
            // Replace Yao Ming with McGrady
            head.next = curr;
            // Back to McGrady
            return curr;
        }
        // Recursively inverts the next node of the current node curr, and the return value is the previous node of the current node after the linked list is inverted
        Node pre = reverse(curr.next);
        // pre for McGrady
        // curr is James
        // Let the next node of the returned node become the current node curr
        pre.next = curr;
        // Make the next node of the current node null
        curr.next = null;
        return curr;
    }
    public static void main(String[] args) {
        // Create a one-way linked list object
        LinkList<String> sl = new LinkList<String>();
        // Test insertion
        sl.insert("Yao Ming");
        sl.insert("Kobe");
        sl.insert("McGrady");
        sl.insertBefore(2, "James");
        for (Object s : sl) {
            System.out.println((String) s);
        }
        System.out.println("--------------------------------");
        sl.reverse();
        for (Object s : sl) {
            System.out.println((String) s);
        }
    }
Output:
Yao Ming
 Kobe
 James
 McGrady
--------------------------------
McGrady
 James
 Kobe
 Yao Ming

1.2.5 speed pointer

Speed pointer refers to the definition of two pointers. The moving speed of these two pointers is slow one by one, so as to create the difference you want. This difference can be adjusted

We find the corresponding node on the linked list. In general, the moving step of the fast pointer is twice that of the slow pointer

1.2.5.1 intermediate value problem

  public static void main(String[] args) throws Exception {
        //Create node
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);

        //Complete the pointing between nodes
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;

        //Find intermediate value
        String mid = getMid(first);
        System.out.println("The median value is:"+mid);
    }

    /**
     * @param first The first node of the linked list
     * @return The value of the intermediate node of the linked list
     */
    public static String getMid(Node<String> first) {
        //Define two pointers
        Node<String> slow = first;
        Node<String> fast = first;
        //Use two pointers to traverse the linked list. When the node pointed by the fast pointer has no next node, it can end. After that, the node pointed by the slow pointer is the intermediate value
        while (fast!=null && fast.next!=null){
            // Quick pointer
            fast = fast.next.next;
            // Slow pointer
            slow = slow.next;
        }
        return slow.item;
    }

    //Node class
    private static class Node<T> {
        //Store data
        T item;
        //Next node
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
Output: Intermediate Value: dd

1.2.5.2 is there a ring problem in the one-way linked list

Requirements:

Please improve the isCircle method in the Test class to return whether there are rings in the linked list.

The idea of using the speed pointer is to compare the linked list to a runway. If there are rings in the linked list, then this runway is a circular runway, in a circular runway

If there is a speed difference between two people, sooner or later they will meet. As long as they meet, it means there is a ring.

    public static void main(String[] args) throws Exception {
        //Create node
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);

        //Complete the pointing between nodes
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;
//        //Generating ring
//        seven.next = third;

        //Judge whether there are links in the linked list
        boolean circle = isCircle(first);
        System.out.println("first Whether there are links in the linked list:"+circle);
    }

    /**
     * Judge whether there are links in the linked list
     * @param first First node of linked list
     * @return ture Is ring, false is acyclic
     */
    public static boolean isCircle(Node<String> first) {
        //Define speed pointer
        Node<String> fast = first;
        Node<String> slow = first;

        //Traverse the linked list. If the speed pointer points to the same node, it proves that there is a ring
        while(fast!=null && fast.next!=null){
            //Transform fast and slow
            fast = fast.next.next;
            slow = slow.next;
            if (fast.equals(slow)){
                return true;
            }
        }

        return false;
    }

    //Node class
    private static class Node<T> {
        //Store data
        T item;
        //Next node
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
Output: first Whether there are links in the linked list: false

1.2.5.3 problem of linked list entry

Requirements:

Please improve the getentry method in the Test class to find the entry node of the link in the linked list.

When the fast and slow pointers meet, we can judge that there are links in the linked list. At this time, we can reset a new pointer to the starting point of the linked list, and the step length is the same as that of the slow pointer

If it is 1, the place where the slow pointer meets the "new" pointer is the entrance of the ring. Proving this conclusion involves the knowledge of number theory, which is omitted here and only about realization.

  public static void main(String[] args) throws Exception {
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);

        //Complete the pointing between nodes
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;
        //Generating ring
        seven.next = third;

        //Find the entry node of the ring
        Node<String> entrance = getEntrance(first);
        System.out.println("first The entry node elements of the link in the linked list are:"+entrance.item);
    }

    /**
     * Find the entry node of a ring in a linked list
     * @param first First node of linked list
     * @return Entrance node of ring
     */
    public static Node getEntrance(Node<String> first) {
        //Define speed pointer
        Node<String> fast = first;
        Node<String> slow = first;
        Node<String> temp = null;
        //Traverse the linked list, first find the ring (the fast and slow pointers meet), prepare a temporary pointer, point to the first node of the linked list, and continue to traverse until the slow pointer meets the temporary pointer. Then the node pointed to when meeting is the entrance of the ring
        while(fast!=null && fast.next!=null){
            //Transform speed pointer
            fast = fast.next.next;
            slow = slow.next;
            if (fast.equals(slow)){
                temp = first;
                continue;
            }

            // Let temporary nodes transform
            if (temp!=null){
                temp = temp.next;
                // Judge whether the temporary pointer meets the slow pointer
                if (temp.equals(slow)){
                    break;
                }
            }
        }
        return temp;
    }
    //Node class
    private static class Node<T> {
        //Store data
        T item;
        //Next node
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
Output: first The entry node elements of the link in the linked list are: cc

1.2.6 circular linked list

Circular linked list, as the name suggests, the whole linked list should form a circular ring. In a one-way linked list, the pointer of the last node is null and does not point to any node

Point, because there is no next element. To realize the circular linked list, we only need to make the pointer of the last node of the one-way linked list point to the head node

1.2.7 problems

Problem Description:

It is said that after the Romans occupied jotapat, 39 Jews hid in a cave with Joseph and his friends, and 39 Jews died

He would rather die than be caught by the enemy, so he decided to commit suicide. 41 people lined up in a circle. The first person counted off from 1 and went to

Later, if someone counts to 3, the person must commit suicide, and then his next person starts counting again from 1 until everyone commits suicide

Until death. However, Joseph and his friends did not want to comply. So Joseph asked his friend to pretend to obey first. He arranged his friend with himself in the 16th

And the 31st position to escape the death game.

Problem conversion:

41 people sit in a circle. The first person is numbered 1, the second person is numbered 2, and the nth person is numbered n.

1. The person with number 1 starts to count off from 1, then back in turn, and the person with number 3 exits the circle;

2. The next person starting from the person who quit will count off from 1 again, and so on;

3. Find the number of the person who quit last.

Illustration:

Problem solving ideas:

1. Build a one-way circular linked list with 41 nodes, and store the values of 1 ~ 41 respectively, representing the 41 people respectively;

2. Use the counter count to record the value of the current number;

3. Traverse the linked list once per cycle, count + +;

4. Judge the value of count. If it is 3, delete the node from the linked list, print the value of the node, and reset the count to 0;

 public static void main(String[] args) {
        // Solve the Joseph problem

        //1. Build a circular linked list, which contains 41 nodes and stores values of 1 ~ 41 respectively
        // First: first node
        // pre: used to record the previous node
        Node<Integer> first = null;
        Node<Integer> pre = null;
        for (int i = 1; i <= 41; i++) {
            //  If it is the first node
            if (i == 1) {
                first = new Node<Integer>(i, null);
                pre = first;
                continue;
            }
            // If not the first node
            Node<Integer> newNode = new Node(i, null);
            pre.next = newNode;
            pre = newNode;
            // If it is the last node, the next node is first
            if (i == 41) {
                pre.next = first;
            }
        }
        // 2. count counter required
        int count = 0;
        // 3. Traverse the circular linked list
        // Record the nodes obtained in each traversal, starting from the first node by default
        Node<Integer> n = first;
        // Record the previous node of the current node
        Node<Integer> before = null;
        while (n != n.next) {
            // Analog counting
            count++;
            // Judge whether the current number of reports is 3
            if (count == 3) {
                // If it is 3, delete the current node, print the current node, reset count=0, and move the current node n backward
                before.next = n.next;
                System.out.print(n.item+",");
                count=0;
                n = n.next;
            } else {
                // If it is not 3, let before become the current node and move the current node backward
                before = n;
                n = n.next;
            }
        }
        // Print the last element
        System.out.println(n.item);
    }


    private static class Node<T> {
        //Store data
        T item;
        //Next node
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
Output:
3,6,9,12,15,18,21,24,27,30,33,36,39,1,5,10,14,19,23,28,32,37,41,7,13,20,26,34,40,8,17,29,38,11,25,2,22,4,35,16,31

1.3 stack

1.3.1.1 stack in life

The place where goods are stored or passengers stay can be extended to warehouse and transfer station. For example, the hotel in our life now was called an inn in ancient times for tourists

In the rest place, passengers can enter the inn to rest and leave the inn after rest.

1.3.1.2 stack in computer

We introduce the concept of stack in life into the computer, which is a place for data to rest. It is a data structure, and data can enter the stack,

You can get out of the stack again.

Stack is a data structure based on first in last out (FILO). It is a special linear table that can only be inserted and deleted at one end. It follows the principle of first in and last out

The first data is pushed into the bottom of the stack, and the last data is at the top of the stack. When you need to read data, pop up data from the top of the stack (the last one)

Data is read first).

We call the action of data entering the stack as pressing the stack, and the action of data leaving the stack as bouncing the stack.

1.3.2 implementation of stack

1.3.2.1 stack API design

1.3.2.2 stack code implementation
public class StackList<T> implements Iterable<T> {

    // Record first node
    private Node head;

    // Number of elements in the current stack
    private int N;

    public StackList() {
        this.head = new Node(null, null);
        this.N = 0;
    }

    /**
     * Judge whether the stack is empty, return true if yes, and return false if No
     *
     * @return
     */
    public boolean isEmpty() {
        return N == 0;
    }

    /**
     * Gets the number of elements in the stack
     *
     * @return
     */
    public int size() {
        return N;
    }

    /**
     * Push element t into the stack
     *
     * @return
     */
    public void push(T t) {
        // Find the first node that the first node points to
        Node<T> oldFirst = head.next;
        // Create a new node
        Node<T> newNode = new Node(t, null);
        // Let the first node point to the new node
        head.next = newNode;
        // Let the new node point to the original first node
        newNode.next = oldFirst;
        // Number of elements + 1
        N++;
    }

    /**
     * Pop up stack top element
     *
     * @return
     */
    public T pop() {
        // Find the first node that the first node points to
        Node<T> oldFirst = head.next;
        if (oldFirst == null) {
            return null;
        }
        // Let the first node point to the next node of the original first node
        head.next = oldFirst.next;
        // Number of elements - 1
        N--;
        return oldFirst.item;
    }

    public Iterator<T> iterator() {
        return new SIterator();
    }

    private class SIterator implements Iterator<T>{

        private Node<T> curr;

        public SIterator() {
            this.curr = head;
        }

        public boolean hasNext() {
            return curr.next!=null;
        }

        public T next() {
            curr = curr.next;
            return curr.item;
        }

        public void remove() {

        }

    }


    private static class Node<T> {
        //Store data
        T item;
        //Next node
        Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }


}
    public static void main(String[] args) {
        //Create stack object
        StackList<String> stack = new StackList();

        //Test stack
        stack.push("a");
        stack.push("b");
        stack.push("c");
        stack.push("d");

        for (String item : stack) {
            System.out.println(item);
        }
        System.out.println("------------------------------");
        //Test cartridge stack
        String result = stack.pop();
        System.out.println("The pop-up elements are:"+result);
        System.out.println("Number of elements remaining:"+stack.size());

    }
Output:
d
c
b
a
------------------------------
The pop-up elements are: d
 Number of remaining elements: 3
  

1.3.3 cases

1.3.3.1 bracket matching problem

Problem Description:

Given a string, it may contain"()"Parentheses and other characters, please write a program to check whether the parentheses in the string appear in pairs.
For example:
"(Shanghai)(Chang'an)": Correct match
"Shanghai((Chang'an))": Correct match
"Shanghai(Chang'an(Beijing)(Shenzhen)Nanjing)":Correct match
"Shanghai(Chang'an))": Wrong match
"((Shanghai)Chang'an": Wrong match

Example code:

public class BracketsMatchTest {
    public static void main(String[] args) {
        String str = "Shanghai(Chang'an)(())";
        boolean match = isMatch(str);
        System.out.println(str + "Whether the brackets in match:" + match);
        System.out.println();
    }

    /**
     * Determine whether the parentheses in str match
     *
     * @param str A string of parentheses
     * @return If it matches, it returns true. If it doesn't match, it returns false
     */
    public static boolean isMatch(String str) {
        //1. Create a stack object to store the left parenthesis
        StackList<String> chars = new StackList();
        //2. Traverse the string from left to right
        for (int i = 0; i < str.length(); i++) {
            String currChar = String.valueOf(str.charAt(i));
            //3. Judge whether the current character is an open bracket. If so, put the character into the stack
            if (currChar.equals("(")) {
                chars.push(currChar);
            } else if (currChar.equals(")")) {
                //4. Continue to judge whether the current character has brackets. If so, an open bracket will pop up from the stack,
                // And judge whether the pop-up result is null. If it is null, it proves that there is no matching left parenthesis,
                // If it is not null, it proves that there is a matching left parenthesis
                String pop = chars.pop();
                if (pop == null) {
                    return false;
                }
            }
        }
        //5. Judge whether there are left parentheses in the stack. If so, it proves that the parentheses do not match
        if (chars.size() == 0) {
            return true;
        } else {
            return false;
        }
    }
}
Output:
Shanghai(Chang'an)(())Whether the brackets in match: true
1.3.3.2 evaluation of inverse Polish expression

The evaluation of inverse Polish expression is a kind of problem we often encounter in computers. To study and understand this problem, we must first find out what inverse wave is

LAN expression? To understand the inverse Polish expression, we have to start with infix expression.

Infix expression:

Infix expressions are expressions used in our daily life, such as 1 + 3 * 2,2 - (1 + 3), etc. infix expressions are characterized by binary operators

Is placed between two operands.

Infix expression is people's favorite expression method, because it is simple and easy to understand. But this is not the case for computers, because infix expressions

The operation order is not regular. Different operators have different priorities. If the computer executes infix expression, it needs to parse the expression semantics and do

A large number of priority related operations.

Inverse Polish expression (suffix expression):

Inverse Polish expression is a representation method of expression, suffix table, first proposed by Polish logician J. lukasewicz in 1929

The characteristic of expression: the operator is always placed after the operand related to it.

public class ReversePolishNotationTest {

    public static void main(String[] args) {
        //The inverse Polish expression of infix expression 3 * (17-15) + 18 / 6 is as follows
        String[] notation = {"3", "17", "15", "-", "*", "18", "6", "/", "+"};
        int result = caculate(notation);
        System.out.println("The result of the inverse Polish expression is:" + result);
        System.out.println(3 * (17 - 15) + 18 / 6);
    }

    /**
     * @param notaion Array representation of inverse Polish expression
     * @return Calculation results of inverse Polish expression
     */
    public static int caculate(String[] notaion) {
        //1. Define a stack to store operands
        StackList<Integer> oprands = new StackList();
        //2. Traverse the inverse Polish expression from left to right to get each element
        for (int i = 0; i < notaion.length; i++) {
            String curr = notaion[i];
            Integer o1;
            Integer o2;
            Integer result;
            //3. Judge whether the current element is an operator or an operand
            switch (curr) {
                //4. Operator, pop up two operands from the stack, complete the operation, and press the calculated result into the stack
                case "+":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 + o1;
                    oprands.push(result);
                    break;
                case "-":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 - o1;
                    oprands.push(result);
                    break;
                case "*":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 * o1;
                    oprands.push(result);
                    break;
                case "/":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2 / o1;
                    oprands.push(result);
                    break;
                default:
                    oprands.push(Integer.parseInt(curr));
                    //5. Operand, put the operand into the stack;
                    break;
            }
        }
        //6. Get the last element in the stack, which is the result of the inverse Polish expression
        int result = oprands.pop();
        return result;
    }

}
Output:
The result of the inverse Polish expression is: 9
9

1.4 queue

Queue is a data structure based on first in first out (FIFO). It is a special linear table that can only be inserted at one end and deleted at the other end

The data is stored according to the principle of first in first out. The data that enters first is read out first when reading the data.

1.4.1 API design of queue

1.4.2 implementation of queue
public class Queue<T> implements Iterable<T> {
    //Record first node
    private Node head;
    //Record the last node
    private Node last;
    //Record the number of elements in the queue
    private int N;

    public Queue() {
        this.head = new Node(null, null);
        this.last = null;
        N = 0;
    }

    //Judge whether the queue is empty
    public boolean isEmpty() {
        return N == 0;
    }

    //Returns the number of elements in the queue
    public int size() {
        return N;
    }

    //Insert element t into queue
    public void enqueue(T t) {
        // Current tail node last = null
        if (last == null) {
            last = new Node(t, null);
            head.next = last;
        } else {
            // Current tail node last= null
            Node oldLast = last;
            last = new Node(t, null);
            oldLast.next = last;
        }
        // Number of elements + 1
        N++;
    }

    //Take an element from the queue
    public T dequeue() {
        if (isEmpty()) {
            return null;
        }
        Node oldFirst = head.next;
        head.next = oldFirst.next;
        N--;
        //Because leaving the queue is actually deleting elements, if the elements in the queue are deleted, you need to reset last=null;
        if (isEmpty()) {
            last = null;
        }

        return oldFirst.item;
    }


    @Override
    public Iterator<T> iterator() {
        return new QIterator();
    }

    private class QIterator implements Iterator {
        private Node n;

        public QIterator() {
            this.n = head;
        }

        @Override
        public boolean hasNext() {
            return n.next != null;
        }

        @Override
        public Object next() {
            n = n.next;
            return n.item;
        }

        @Override
        public void remove() {

        }
    }

    private class Node {
        public T item;
        public Node next;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }

}
    public static void main(String[] args) {
        //Create queue object
        Queue<String> q = new Queue<>();

        //enqueue method of test queue
        q.enqueue("a");
        q.enqueue("b");
        q.enqueue("c");
        q.enqueue("d");

        for (String str : q) {
            System.out.println(str);
        }

        System.out.println("-------------------------------");
        //dequeue method of test queue
        String result = q.dequeue();
        System.out.println("The out of queue elements are:"+result);
        System.out.println("Number of elements remaining:"+q.size());

    }
Output:
a
b
c
d
-------------------------------
The out of queue elements are: a
 Number of remaining elements: 3

Topics: data structure linked list