1. Characteristics of queues
  2. One-way queue
  3. The circular queue
  4. Singly linked list
  5. Two-way linked list
  6. Circular linked list

The following ideas and key methods are only given. The source code of the algorithm is put in Git, and you need to take it yourself

Gitee.com/leidl97/alg…

Characteristics of queues

First in, first out (FIFO)

Can be interpreted as queuing, first in line first in. As is shown in

It’s from the Fourth Edition of Algorithms, page 78

One-way queue

Ideas (how to define data)

It is implemented as an array. The first position of the head pointer to the beginning is -1, and the default position is 0

The position where the tail pointer points to the last element is also -1. (In the initial case, there are no elements, so it points to -1. When the element is added, the tail pointer +1 adds the value to the last element.)

Check that the queue is full

The tail pointer points to the last position of the element

Determine that the queue is empty

Head pointer = tail pointer

In the data

First move, then take. Let the tail pointer +1 first, before assigning the value to the position of the tail pointer

Take out the data

First move, then take. To fetch the tail data, first set the head pointer to +1 to fetch the position to which the head pointer points

Java implementation

Write the queue entry and exit methods, usually in an array

Attribute definitions

// The maximum size of the array
private int maxSize;
/ / queue head
private int begin;
/ / queue tail
private int end;
// An array of queues
private int[] arr;

public ArrayQueue(int maxSize){
    // This can be omitted, but it is clearer to write
    this.maxSize = maxSize;
    this.arr = new int[maxSize];
    // The queue header points to the position before the start
    this.begin = -1;
    // The end of the queue points to the last position. They're both -1 but they don't mean the same thing
    this.end = -1;
}
Copy the code

Judge team full

// If the queue is not full, the end of the queue is the last element of the array
public boolean isFull(a){
    return this.end == this.maxSize - 1;
}
Copy the code

Judge team empty

// Check whether the queue is empty
public boolean isEmpty(a){
    return this.begin == this.end;
}
Copy the code

Add data to the queue

// Add data to the queue
public void addQueue(int data){
	// Check to see if it is full
	if (isFull()) {
		throw new RuntimeException("Queue full, cannot add data");
	}
	this.arr[++this.end] = data;
}
Copy the code

Get queue data

// Get the data from the queue
public int getQueue(a){
    if (isEmpty()) {
        // Throw an exception without writing return
        throw new RuntimeException("Queue empty, no data can be fetched.");
    }
    return this.arr[++this.begin];
}
Copy the code

Display queue data

// Get the data from the queue
public int getQueue(a){
    if (isEmpty()) {
        // Throw an exception without writing return
        throw new RuntimeException("Queue empty, no data can be fetched.");
    }
    return this.arr[++this.begin];
}
Copy the code

Display queue header data

// Display the queue header data
public int getBegin(a){
     if (isEmpty()) {
     throw new RuntimeException("This team is listed as empty.");
     }
     return this.arr[begin+1];
}
Copy the code

defects

Can not reuse, use once obsolete, can not frequently add and delete elements, the solution is to use a ring queue

The circular queue

thought

Can you think about what you need to do to reuse, yes, take modules

So when you define an array, you sacrifice a space for judgment

The difference is, we define a header pointer to the first element, which is 0

The tail pointer to the next position at the end of the array is also 0

Determine that the queue is empty

Head pointer = tail pointer. Like in the beginning

Check that the queue is full

(tail pointer +1) % array size is 0 when the queue is full

In the data

Unlike unidirectional, this time there is a shift. Saves the region pointed to by the tail pointer to the specified data, and then moves to the next location

Take out the data

Take first and then move. Retrieves the element to which the current head pointer points, and then moves to the next position

Get all elements

You have to figure it out, right? How should I fill in the position of

for(int i = ? ; i < ? ; i++)Copy the code

The first one? Should be the subscript of the element to which the current header pointer points

The second one? The current header pointer should be subscript + the number of valid elements

If not, then you need to determine which of the two Pointers is in front and which is behind

Get a significant number

(tail pointer – head pointer + array size)% Array size

That’s the absolute value of the tail pointer – the head pointer

Java implementation

Attribute definitions

     // The maximum size of the array
     private int maxSize;
     / / queue head
     private int begin;
     / / queue tail
     private int end;
     // An array of queues
     private int[] arr;
 
     // If the header points to the first element and the tail points to the last element, the initial state cannot be determined as empty or full
     // Add the data tail pointer to move, fetch the data header pointer to move, this design sacrifice a space, that is, by default, the last location does not store data
     public CircleArrayQueue(int maxSize){
         // This can be omitted, but it is clearer to write
         this.maxSize = maxSize;
         this.arr = new int[maxSize];
         // The queue header points to the first position of the element
         this.begin = 0;
         // The end of the queue points to the last position of the element
         this.end = 0;
     }
Copy the code

Judge team full

     Maxsize = tail: the head is always pointing to the first element. The tail is full (the last element +1).
     public boolean isFull(a){
         return (this.end + 1)%maxSize == this.begin;
     }
Copy the code

Judge team empty

     // Check whether the queue is empty
     public boolean isEmpty(a){
         return this.begin == this.end;
     }
Copy the code

Add data

     // Add data to queue, tail pointer +1
     public void addQueue(int data){
         // Check to see if it is full
         if (isFull()) {
             throw new RuntimeException("Queue full, cannot add data");
         }
         arr[end] = data;
         end = (end + 1) % maxSize;
         System.out.println("Save data:"+data);
     }
Copy the code

Get queue header data

     // Get queue data, header pointer +1
     public int getQueue(a){
         if (isEmpty()) {
             // Throw an exception without writing return
             throw new RuntimeException("Queue empty, no data can be fetched.");
         }
         int data = arr[begin];
         begin = (begin + 1) % maxSize;
         System.out.println("Fetch data :"+data);
         return data;
     }
Copy the code

Displays all data in the queue

     // Display all data in the queue.
     public void getAllQueue(a){
         StringBuffer sb = new StringBuffer();
         if (isEmpty()) {
             throw new RuntimeException("This team is listed as empty.");
         }
         for (int i = begin; i< begin+getActive(); i++) {
             System.out.println("arr["+i%maxSize+"] ="+arr[i%maxSize]); }}Copy the code

Displays valid data for the queue

     // Displays valid data for the queue
     public int getActive(a){
         return (end + maxSize - begin) % maxSize;
     }
Copy the code

The list

Linked list is an ordered list with an address, a data field for storing data, and a next field for pointing to the next address

Linked lists are stored as nodes

Each node contains the data field, and the next field

It doesn’t have to be continuous storage

Images from the Internet

Singly linked list

Train of thought

Start by defining a Node class Node

There are ID, data, and at least three attributes of the next node

Define a node class that initializes the head node, and since the head node cannot move, define secondary nodes for addition and traversal

Add: The end interpolation method, determine whether the next element of the current element is empty, if so, insert the next node in the current node, if not in order to find the next empty node and then insert

Traversal: first determine whether the next element of the head node is empty, otherwise look down, and then output the node once

Disadvantages: Cannot be added in serial order

Java implementation

The test part

         MangerNode mangerNode = new MangerNode();
         Node node1 = new Node(1."Wife Number one");
         Node node2 = new Node(2."Wife Number two");
         Node node3 = new Node(3."Wife Number three");
         Node node4 = new Node(4."Wife Number four.");
         mangerNode.add(node1);
         mangerNode.add(node2);
         mangerNode.add(node3);
         mangerNode.add(node4);
         mangerNode.show();
Copy the code

Define the nodes

     // Marks the current node number
     public int no;
     / / data domain
     public String data;
     // Next node
     public Node next;
 
     public Node(int no, String data){
         this.no = no;
         this.data = data;
     }
Copy the code

Add a node

     // Add a node
     public void add(Node node){
         temp = head;
         while (true) {
             if (temp.next == null) {
                 break;
             }
             temp = temp.next;
         }
         temp.next = node;
     }
Copy the code

Traversing the list

     // Iterate over the list
     public void show(a){
         temp = head.next;
         // Check whether it is null
         if(temp == null) {
             System.out.println("Linked list is empty");
         } else {
             while (true) {
                 System.out.println(temp);
                 if (temp.next == null) {break; } temp = temp.next; }}}Copy the code

If you want to add them in order of number

You have to go through and judge. Start from the head node, use temp as an auxiliary variable to point to the head node, determine whether the serial number of the next element no is greater than the inserted node, if so, find the current element. If equal, the node is repeated, otherwise the loop continues until the next element is empty

Add the following code

 // Add a node (advanced version)
 public void addPro(Node node){
     temp = head;
     // There are no repeating elements by default
     boolean flag = false;
     while (true) {
         if (temp.next == null) {
             break;
         }
         if (temp.next.no > node.no) {
             break;
         } else if (temp.next.no == node.no) {
             flag = true;
             break;
         }
         temp = temp.next;
     }
     // Add elements
     if (flag) {
         System.out.println("There is no for"+node.no+"Duplicate elements may not be added");
     } else{ node.next = temp.next; temp.next = node; }}Copy the code

Modify: directly modify after finding

 // Find the modification
     public void update(Node node){
         if (head.next == null) {
             System.out.println("The list is empty!");
         } else {
             temp = head.next;
             while (true) {
                 if (temp.next == null) {break;
                 }
                 if (temp.no == node.no) {
                     temp.data = node.data;
                     break; } temp = temp.next; }}}Copy the code

Delete: in addition to finding the node B to be deleted, we also need to find the previous node A, which used to point to B, now A points to C, and finally delete B (directly assigning is equivalent to deleting).

// find A pointing to B instead of pointing to C and delete B
    public void delete(Node node){
        if (head.next == null) {
            System.out.println("The list is empty!");
        } else {
            temp = head;
            while (true) {
                if (temp.next == null) {break;
                }
                if (temp.next.no == node.no) {
                    temp.next = temp.next.next;
                    break; } temp = temp.next; }}}Copy the code

List inversion

Train of thought

It’s the old linked list and the current linked list

The important core steps are

1. The current node (cur) points to the next node of the new head node (new.next).

2. The next header of the new node (new.next) points to the current node (cur).

Draw a diagram

First move

Second movement

Code implementation

public void reverse(Node headNode){
        // Returns the result when there is no node or only one node
        if (headNode.next == null || headNode.next.next == null) {
            System.out.println("The list is empty!");
        }

        // Define an auxiliary variable, cur, to iterate over the original list
        Node cur = headNode.next;
        // Define the next node for cur, next, to record
        Node next = null;
        // Define the head node of the new node
        Node newHead = new Node(0."");
        while(cur ! =null) {
            // Next points to the next node for cur
            next = cur.next;
            // The next node of cur points to the next node of the new head node
            cur.next = newHead.next;
            // The next node of the new head node points to the cur node
            newHead.next = cur;
            / / a cur
            cur = next;
        }
        // At this point, cur is already a list of linked nodes reversed after head. The new node is transferred to the original node to reverse the original node
        headNode.next = newHead.next;
    }
Copy the code

Effect of screenshots

Two-way linked list

Train of thought

Unlike a one-way linked list, attributes add a Pre that points to the previous node

Add, delete, change and check to make some changes, but also easy to implement

Added: In addition to needing to point to the next, you now need to point to the previous one

Delete: After finding the node to be deleted, use the previous node to point to the next node, and the same last node also points to the previous node.

Modify: This does not change, after the node finds the specific element, modify the data

Query: Next traversal, pre traversal can be done

Note: Implementing the toString method with next and pre will overflow the stack and cause a pit

Java implementation

The test part

        DoubleNode node1 = new DoubleNode(1."Wife Number one");
        DoubleNode node2 = new DoubleNode(2."Wife Number two");
        DoubleNode node3 = new DoubleNode(3."Wife Number three");
        // Update the node
        DoubleNode node4 = new DoubleNode(1."Wife Number four");
        ManagerDoubleNode.add(node1);
        ManagerDoubleNode.add(node2);
        ManagerDoubleNode.add(node3);
// ManagerDoubleNode.delete(node3.getNo());
        ManagerDoubleNode.update(node4);
        ManagerDoubleNode.show();
Copy the code

Node definition

    // Define the node number
    private int no;
    // Define the previous node
    public DoubleNode pre;
    // Define data
    public String data;
    // Define the latter node
    public DoubleNode next;

    DoubleNode(int no, String data) {
        this.no = no;
        this.data = data;
    }
Copy the code

Add node

    // Add a node
    public static void add(DoubleNode node) {
        DoubleNode temp = ManagerDoubleNode.head;
        while(temp.next ! =null) {
            temp = temp.next;
        }
        temp.next = node;
        node.pre = temp;
    }
Copy the code

Delete nodes

    // Delete a node
    public static void delete(int no) {
        DoubleNode temp = ManagerDoubleNode.head.next;
        boolean flag = false;
        while(temp ! =null) {
            if (temp.getNo() == no) {
                // Find the node and delete it
                flag = true;
                temp.pre.next = temp.next;
                if(temp.next ! =null) {
                    // If the node is not the last, its next node points to the previous node of temp
                    temp.next.pre = temp.pre;
                }
                break;
            }
            // If you cannot find it, move to the next position
            temp = temp.next;
        }
        if (flag) {
            System.out.println("This node has been deleted!");
        } else {
            System.out.println("This node does not exist and cannot be deleted!"); }}Copy the code

Update the node

    public static void update(DoubleNode node) {
        DoubleNode temp = ManagerDoubleNode.head.next;
        boolean flag = false;
        while(temp ! =null) {
            if (temp.getNo() == node.getNo()) {
                // Find the node and update it
                flag = true;
                temp.data = node.data;
                break;
            }
            // If you cannot find it, move to the next position
            temp = temp.next;
        }
        if (flag) {
            System.out.println("This node is updated!");
        } else {
            System.out.println("This node does not exist and cannot be updated!"); }}Copy the code

Show nodes

    public static void show(a) {
        DoubleNode temp = ManagerDoubleNode.head.next;
        while(temp ! =null) { System.out.println(temp); temp = temp.next; }}Copy the code

Circular linked list

One way circular linked list

Implementation ideas and code

Same node definition as before, number, data field, next point to

Add, delete, alter, and check are slightly different. Next does not now point to null, even if only one element points to itself

To determine the end condition change, you need to determine whether the next node of the current node is the head node

Walk through the code implementation

public CircleNode show(a) {
        cur = first;
        while (true) {
            System.out.println(cur);
            if (cur.next == first) {
                break;
            }
            cur = cur.next;
        }
        return cur;
    }
Copy the code

Increase constant, find the last position and increase

public void add(CircleNode circleNode) {
        cur = first;
        while (true) {
            if (cur.next == first) {
                break;
            }
            cur = cur.next;
        }
        cur.next = circleNode;
        circleNode.next = first;
    }
Copy the code

Change it. Find the corresponding no and change it

It should be noted that there is no end judgment condition, so no judgment should be made first and then traversal judgment should be made once

Otherwise, if there are no elements that need to be modified, just keep looking for them and delete them

public void update(int no, String data) {
        cur = first;
        while (true) {
            if (cur.no == no) {
                cur.data = data;
                System.out.println("Data modified successfully!");
                break;
            }
            if (cur.next == first) {
                System.out.println("No data to modify found!");
                break; } cur = cur.next; }}Copy the code

Note that: if the head node is to be deleted, the head node needs to be transformed. Here, I extend the head node, and then make the previous one of the node to be deleted point to the modified head node. Because it is a single linked list, the next one of the current node needs to be traversed

public void delete(CircleNode circleNode) {
        cur = first;
        while (true) {
            if (cur.next.no == circleNode.no) {
                if (cur.next == first) {
                    first = cur.next.next;
                    cur.next = first;
                    System.out.println("Deleted data is the head node, the current head node continues as"+first);
                    break;
                }
                cur.next = cur.next.next;
                System.out.println("Data deleted successfully!");
                break;
            }
            if (cur.next == first) {
                System.out.println("No data found to delete!");
                break; } cur = cur.next; }}Copy the code

If you specify the size of a circular list, it is important to initialize it in the method, not at object creation time, at I =1, and then add nodes

public MangerCircleNode addByNum(int num) {
    	if (num < 1) {
            System.out.println("Size can't be less than 1!");
            return null;
        }
        MangerCircleNode mangerCircleNode = new MangerCircleNode();
        CircleNode newNode = null;
        for (int i = 1; i<=num; i++) {
            if (i == 1) {/ / initialization
                mangerCircleNode.first = new CircleNode(i,"Wife"+i+"No.");
                mangerCircleNode.first.next = mangerCircleNode.first;
                cur =mangerCircleNode.first;
            } else {
                // Add a ring node
                newNode = new CircleNode(i,"Wife"+i+"No.");
                cur.next = newNode;
                newNode.next = mangerCircleNode.first;
            }
            //cur points to the next node
            cur = cur.next;
        }
        return mangerCircleNode;
    }
Copy the code

Practical classic problem: Joseph problem

Numbers for 1, 2,… ,n of n people sitting in a clockwise circle, each with a number (positive integer). From the NTH number, counting clockwise from the first person starting at 1, stop counting when reporting m. The person calling m goes out, and the next person counts, and so on, until everyone is out. Try to design a program to figure out the column order. The basic requirement is to use the storage structure of one-way circular linked list to simulate this process, and print out the number of each person in the order of the column. After the implementation of the prompt program, the user is required to specify the initial upper limit value, and then read each password. Can set n 30 or less. There is no need for “headers” in the circular linked list used in this question. Note the distinction between empty and non-empty tables.

Images from the Internet

Images from the Internet

And so on

Images from the Internet

Simulation: pass in a m, which means traversal once every m times, and output the result after traversal finally

public void yusefu(int m){
    int count = getCount();
    if (m > count) {
        System.out.println("The number entered cannot be larger than the list size");
    } else {
        / / reset
        cur = first;
        while (true) {
            if (count == 0) {
                break;
            }
            for (int j = 0; j<m-1; j++){
                cur = cur.next;
            }
            System.out.println(cur);
            first = cur.next;
            this.delete(cur); cur = first; count--; }}}// Get the number of lists
public int getCount(a) {
    cur = first;
    int count = 0;
    while (true) {
        count++;
        if(cur.next == first){
            break;
        }
        cur = cur.next;
    }
    return count;
}
Copy the code

Enhanced version, input three numbers, output traversal results

From the number, how many times, how big a list to create

Simulate a real problem

Count from the number of children, count how many times, how many children there are

Note the scope of variables

/ * * * *@paramStartNo From what number *@paramCountNo how many times *@paramHow many people are there in total
    public void yusefu(int startNo, int countNo, int size){
        if (startNo < 1 || countNo < 1 || size < 1 || startNo > size) {
            System.out.println("The numbers don't add up!");
            return;
        }
        MangerCircleNode mangerCircleNode = new MangerCircleNode(size);
        // Check which node is first. This node is already a loop
        for (int i = 0; i<startNo-1; i++) {
            mangerCircleNode.first = mangerCircleNode.first.next;
        }
        / / reset
        mangerCircleNode.cur = mangerCircleNode.first;
        while (true) {
            if (size == 0) {
                 System.out.println("The final number of the circle is:"+mangerCircleNode.cur.no);
                break;
            }
            for (int j = 0; j<countNo-1; j++){ mangerCircleNode.cur = mangerCircleNode.cur.next; } System.out.println(mangerCircleNode.cur); mangerCircleNode.first = mangerCircleNode.cur.next; mangerCircleNode.delete(mangerCircleNode.cur); mangerCircleNode.cur = mangerCircleNode.first; size--; }}Copy the code

Added: Sparse array

What is a sparse array?

Change a two-dimensional array into a 3xn array to save space and improve storage efficiency

thought

When most elements of an array are zero, or a fixed value, sparse arrays can be used

Converts a 2×2 two-dimensional array into a 3xn array, as shown in the following table

The application requirements

gobang

Two-dimensional –> sparse

1. Iterate through the original two-dimensional array to get the number of valid data sum

SparseArr int[sum+1][3]

3. Store valid data of two-dimensional array into sparse array

Sparse –> two dimensions

ChessArr = int[row][col] chessArr = int[col]

2. Read the data in the last few lines of the sparse array and assign it to the original two-dimensional array

Java implementation

 public static void main(String[] args) {
         // Create a checkerboard with 0 for unplayed, 1 for black, and 2 for white
         int chessArr[][] = new int[11] [10];
         chessArr[1] [2] = 1;
         chessArr[2] [3] = 2;
         chessArr[3] [4] = 1;
         int k = 0;
         // Outputs the original two-dimensional array
         for (int[] row : chessArr){
             for (int data : row){
                 // Output + TAB in decimal notation
                 System.out.printf("%d\t",data);
                 if(data ! =0){
                     k++;
                 }
             }
             System.out.println();
         }
 
         // select row from col
         int row = chessArr[0].length;
         int col = chessArr.length;
         System.out.println("row="+row+"col="+col);
         int a = 1,b = 0;
         // Create a sparse array
         int sparseArr[][] = new int[k+1] [3];
         sparseArr[0] [0] = col;
         sparseArr[0] [1] = row;
         sparseArr[0] [2] = k;
         for (int i = 0; i<chessArr.length; i++){
             for (int j = 0; j<chessArr[i].length; j++){
                 if(chessArr[i][j] ! =0){
                     sparseArr[a][0] = i;
                     sparseArr[a][1] = j;
                     sparseArr[a][2] = chessArr[i][j]; a++; }}}for (int[] row1 : sparseArr){
             for (int data : row1){
                 // Output + TAB in decimal notation
                 System.out.printf("%d\t",data);
             }
             System.out.println();
         }
         // How to count rows and columns in a group
     }
Copy the code

The output

0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 row=10col=11 11 10 3  1 2 1 2 3 2 3 4 1 Process finished with exit code 0Copy the code