PubMed Data Structure Study Notes 2

1. Linked list

The linked list is different from the sequence table. The bottom layer of the sequence table uses an array as a storage container. It needs to allocate a continuous and complete memory space for use, but the linked list does not need it. It connects the scattered nodes through a pointer to form a chain. The structure, each node stores an element, and a pointer to the next node, connected one by one in this way, and finally forms a linked list. It does not need to apply for continuous space, but only needs to be connected in order. Although they may not be physically adjacent, logically each element is still stored next to each other. This structure is called a linked list (singly linked list).

The linked list is divided into a linked list with a head node and a linked list without a head node. A linked list with a head node will have a head node pointing to the subsequent entire linked list, but the head node does not store data.
image-20220723180221112

A linked list without a leading node is like the above. The first node is the node that stores data. Generally, the structure of the leading node is adopted in the design of the linked list, because the operation is more convenient.

Let's try to define:

public class LinkedList<E> {
    
    
  	//链表的头结点,用于连接之后的所有结点
    private final Node<E> head = new Node<>(null);
  	private int size = 0;   //当前的元素数量还是要存一下,方便后面操作
    
    private static class Node<E> {
    
      //结点类,仅供内部使用
        E element;   //每个结点都存放元素
        Node<E> next;   //以及指向下一个结点的引用
      
      	public Node(E element) {
    
    
            this.element = element;
        }
    }
}

1.1 insert

How to insert the linked list: You can first modify the successor node (that is, the next node) of the newly inserted node to point to the node that was originally at this position, and then we can change the predecessor node (that is, the previous node) node) points to the newly inserted node, so we have successfully inserted a new node, and now the newly inserted node has reached the original second position

public void add(E element, int index){
    
    
    Node<E> prev = head;   //先找到对应位置的前驱结点
    for (int i = 0; i < index; i++) 
        prev = prev.next;
    Node<E> node = new Node<>(element);   //创建新的结点
    node.next = prev.next;   //先让新的节点指向原本在这个位置上的结点
    prev.next = node;   //然后让前驱结点指向当前结点
    size++;   //完事之后一样的,更新size
}

Let's rewrite the toString method to see if it can be inserted normally:

@Override
public String toString() {
    
    
    StringBuilder builder = new StringBuilder();
    Node<E> node = head.next;   //从第一个结点开始,一个一个遍历,遍历一个就拼接到字符串上去
    while (node != null) {
    
    
        builder.append(node.element).append(" ");
        node = node.next;
    }
    return builder.toString();
}
  • Consider whether the insertion position is legal:
public void add(E element, int index){
    
    
    if(index < 0 || index > size)
        throw new IndexOutOfBoundsException("插入位置非法,合法的插入位置为:0 ~ "+size);
    Node<E> prev = head;
    for (int i = 0; i < index; i++)
        prev = prev.next;
    Node<E> node = new Node<>(element);
    node.next = prev.next;
    prev.next = node;
    size++;
}

1.2 delete

After the insertion operation is completed, let's look at the deletion operation, so how do we implement the deletion operation? In fact, it will be simpler, we can directly point the predecessor node of the node to be deleted to the next
image-20220723222922058
image-20220723223103306

In this way, logically speaking, the node to be deleted is no longer in the linked list, so we only need to release the memory space occupied by the node to be deleted
image-20220723223216420

public E remove(int index){
    
    
    if(index < 0 || index > size - 1)   //同样的,先判断位置是否合法
        throw new IndexOutOfBoundsException("删除位置非法,合法的删除位置为:0 ~ "+(size - 1));
    Node<E> prev = head;
    for (int i = 0; i < index; i++)   //同样需要先找到前驱结点
        prev = prev.next;
    E e = prev.next.element;   //先把待删除结点存放的元素取出来
    prev.next = prev.next.next;  //可以删了
    size--;   //记得size--
    return e;
}

In this way, we have successfully completed the delete operation of the linked list.

  • Get the element at the corresponding position:
public E get(int index){
    
    
    if(index < 0 || index > size - 1)
        throw new IndexOutOfBoundsException("非法的位置,合法的位置为:0 ~ "+(size - 1));
    Node<E> node = head;
    while (index-- >= 0)   //这里直接让index减到-1为止
        node = node.next;
    return node.element;
}

public int size(){
    
    
    return size;
}
  • Under what circumstances should you use a sequence table, and under what circumstances should you use a linked list?
    • By analyzing the characteristics of the sequence table and the linked list, it is not difficult to find that the linked list needs to be traversed to complete random access to elements, while the sequence table is directly accessed by using the characteristics of the array. Therefore, when we read more data than insert or When deleting data, it is better to use a sequential table.
    • The sequence table is a bit useless when inserting elements, because the subsequent elements need to be moved, the entire movement operation will waste time, but the linked list does not need it, and the insertion can be completed only by modifying the node pointing, so frequent insertion or deletion In the case of , it is better to use a linked list.

Although the singly linked list is also more convenient to use, there is a problem that if we want to operate a certain node, such as delete or insert, then due to the nature of the singly linked list, we can only find its predecessor node first, to proceed. In order to solve this troublesome problem of finding the predecessor node, we can let the node not only save the pointer to the subsequent node, but also save the pointer to the predecessor node

In this way, no matter which node we are in, we can quickly find the corresponding predecessor node, which is very convenient. We call such a linked list a doubly linked list (double linked list)

2. stack

A stack (also called a stack, Stack) is a special linear table that can only be inserted and deleted at the end of the table
image-20220724210955622

The bottom is called the bottom of the stack, and the top is called the top of the stack. All operations can only be performed on the top of the stack. The books in the box are the same, because there is only one mouth to take out the items inside, so the books that are pressed down can only be taken out after the books above are taken out. This is the idea of ​​​​the stack, which is a first-in last-out The data structure (FILO, First In, Last Out)

It is also very simple to implement a stack, which can be based on our previous sequence list or linked list. Here we need to implement two new operations:

  • pop: pop operation, take an element from the top of the stack.
  • push: push operation, push a new element into the stack.

A stack can be implemented using a sequential list or a linked list

2.1 Push into the stack

When a new element is pushed into the stack, you only need to insert a new node at the head of the linked list. Let's try to write:

public class LinkedStack<E> {
    
    

    private final Node<E> head = new Node<>(null);   //大体内容跟链表类似

    private static class Node<E> {
    
    
        E element;
        Node<E> next;

        public Node(E element) {
    
    
            this.element = element;
        }
    }
}

Push operation:

public void push(E element){
    
    
    Node<E> node = new Node<>(element);   //直接创建新结点
    node.next = head.next;    //新结点的下一个变成原本的栈顶结点
    head.next = node;     //头结点的下一个改成新的结点
}

2.2 pop out

The same is true for popping, so we only need to remove the first element:

public E pop(){
    
    
  	if(head.next == null)   //如果栈已经没有元素了,那么肯定是没办法取的
      	throw new NoSuchElementException("栈为空");
    E e = head.next.element;   //先把待出栈元素取出来
    head.next = head.next.next;   //直接让头结点的下一个指向下一个的下一个
    return e;
}

3. Queue

We learned about the stack earlier. The elements in the stack can only enter and exit from the top of the stack. It is a special linear table. Similarly, the queue (Queue) is also a special linear table.

Just like we need to queue up in supermarkets and cafeterias, we always line up in a row. The people who arrive first are in the front, and the people who come later are in the back. The people who are in the front are the first to complete the task. The head and tail of the queue
image-20220725103600318
adhere to the principle of first come, first served. The elements in the queue can only enter from the tail of the queue and can only go out from the head of the queue. That is to say, the order of entering the queue is 1, 2, 3, 4, so the order of leaving the queue must It is 1, 2, 3, 4, so the queue is a first-in-first-out (FIFO, First In, First Out) data structure.

Queues can also be implemented using linked lists and sequential lists, but if you use linked lists, you don't need to care about capacity and other issues, and it will be more flexible

public class LinkedQueue<E> {
    
    

    private final Node<E> head = new Node<>(null);

    public void offer(E element){
    
      //入队操作
        Node<E> last = head;
        while (last.next != null)   //入队直接丢到最后一个结点的屁股后面就行了
            last = last.next;
        last.next = new Node<>(element);
    }

    public E poll(){
    
       //出队操作
        if(head.next == null)   //如果队列已经没有元素了,那么肯定是没办法取的
            throw new NoSuchElementException("队列为空");
        E e = head.next.element;
        head.next = head.next.next;   //直接从队首取出
        return e;
    }

    private static class Node<E> {
    
    
        E element;
        Node<E> next;

        public Node(E element) {
    
    
            this.element = element;
        }
    }
}

Guess you like

Origin blog.csdn.net/qq_40332045/article/details/130332562