Chapter 4 stack and queue in datastructure of Dahua

Keywords: Java

Article catalog

Chapter 4 stack and queue

Definition of stack:
A linear table that can only be inserted and deleted at the end of the table. We call one end of the table that can be inserted and deleted the top, the other the bottom, and the empty stack without any data elements. Stack is also called last in first out (LIFO structure).
The stack is like a bullet clip. The first one is put in and then comes out. The last one is put in and comes out. Operations such as backward and undo are all implemented by using the stack.

Stack insertion operation: called push stack, also known as push stack, push stack, similar to bullets into the magazine.

Stack delete operation: call out the stack, also known as the bullet stack, just like the bullet pop-up of the magazine.

Note: there are many changes in the stack, not necessarily the first in and last out, maybe in and out.

Abstract data type of stack:

General situation, empty stack, full stack:

Structure definition and access code

Stack structure definition code:

typedef int SElemType;
typedef struct
{
    SElemType data[MAXSIZE];
    int top; // Stack top pointer
}SqStack;

Stack code:

Status Push(SqStack *S, SElemType e)
{
    if (S->top == MAXSIZE - 1) // Stack full
    {
        return ERROR;
    }
    S->top++;    // Stack top pointer backward
    S->data[S->top] = e;    // Assign a new insert element to the top space of the stack
    return OK;
}

Stack out operation:

Status Pop(SqStack *S, SElemType *e)
{
    if (S->top == -1)
    {
        return ERROR;
    }
    *e = S->data[S->top];    // Assign the top of stack element to be deleted to e
    S->top--;    // Stack top pointer-1
    return OK;
}

JAVA implementation stack

Stack class:

public class stack {
    public Object[] data;
    public int top;

    public stack() {
    }
}

class Stack_{
    private int MAXSIZE;
    private stack Sta;

    // initialization
    public Stack_(int MAXSIZE) {
        this.MAXSIZE = MAXSIZE;
        Sta = new stack();
        Sta.data = new Object[MAXSIZE];
        Sta.top = -1;   // Starting from - 1, it is convenient to match the array index
    }

    // Push 
    public void push(Object e){
        // Judge whether the stack is full
        if (Sta.top == MAXSIZE-1)
            throw new IndexOutOfBoundsException("It's full");
        Sta.top++;
        Sta.data[Sta.top] = e;
    }

    public Object pop(){
        if (Sta.top == -1)
            throw new IndexOutOfBoundsException("The stack is already empty and cannot be deleted");

        Object data = Sta.data[Sta.top];
        Sta.data[Sta.top] = null;
        Sta.top--;
        return data;
    }

    public void show(){
        for (int i = 0; i < Sta.top + 1; i++) {
            System.out.println(Sta.data[i]);
        }
    }
}

Test code:

public class main {
    public static void main(String[] args) {
        Stack_ S = new Stack_(3);
        S.push(12);
        S.push(13);
        S.push(14);
        S.show();
        System.out.println("Delete:" + S.pop());
    }
}

Two stacks of shared space

A picture is worth a thousand words:

top1 is the top of stack pointer of stack 1, and top2 is the top of stack pointer of stack 2. Except for the empty stack, when top1 + 1 = top2, the stack is full.

space structure

typedef struct
{
    SElemType data[MAXSIZE];
    int top1;
    int top2;
}SqDoubleStack;

push method:
In addition to inserting, we also need to determine the stack parameters, which stack to write to

Status Push(SqDoubleStack *S, SElemType e, int stackNumber)
{
    if (S->top1 + 1 == S->top2) // Full stack
        return ERROR;
    if (stackNumber == 1) // Go to stack 1
        S->data[++S->top1] = e;    // Assign + change address
    else if (stackNumber == 2)
        S->data[--S->top2] = e;
    return OK;
}

pop method:

Status Pop(SqDoubleStack *S, SElemType *e, int stackNumber)
{
    if (stackNumber == 1)
    {
        if (S->top1 == -1)
            return ERROE;
        *e = S->data[S->top1--];
    }
    else if (stackNumber == 2)
    {
        if (S->top2 == MAXSIZE)
            return ERROR;
        *e = S->data[S->top2++];
    }
    return OK;s
}

This is usually used when two sets of data are put together.

JAVA implementation of dual stack shared space

Double stack class:

public class Stack_ {
    public Object[] data;
    public int top1;
    public int top2;

    public Stack_() {
    }

    public Stack_(int len) {
        this.data = new Object[len];
        this.top1 = -1;
        this.top2 = len;
    }
}

class ShareStack {
    private int MAXSIZE;
    private Stack_ Sta;

    public ShareStack(int MAXSIZE) {
        this.MAXSIZE = MAXSIZE;
        Sta = new Stack_(MAXSIZE);
    }

    public void push(Object e, int StackIdx){
        if (StackIdx!=1 && StackIdx!=2)
            throw new IndexOutOfBoundsException("Wrong number of linked list");
        if (Sta.top1 >= Sta.top2-1)
            throw new IndexOutOfBoundsException("It's full");

        if (StackIdx == 1){
                Sta.top1++;
                Sta.data[Sta.top1] = e;
        } else {
                Sta.top2--;
                Sta.data[Sta.top2] = e;
            }
    }

    public Object pop(int StackIdx) {
        if (StackIdx!=1 && StackIdx!=2)
            throw new IndexOutOfBoundsException("Wrong stack number");



        if (StackIdx == 1){
            if (Sta.top1 == -1){
                throw new IndexOutOfBoundsException("Stack 1 has no content to delete");
            }
            Object data = Sta.data[Sta.top1];
            Sta.data[Sta.top1] = null;
            Sta.top1--;
            return data;
        } else {
            if (Sta.top1 == MAXSIZE){
                throw new IndexOutOfBoundsException("Stack 2 has no content to delete");
            }
            Object data = Sta.data[Sta.top2];
            Sta.data[Sta.top2] = null;
            Sta.top2++;
            return data;
        }
    }

    public void show(int StackIdx){
        if (StackIdx!=1 && StackIdx!=2)
            throw new IndexOutOfBoundsException("Wrong stack number");
        if (StackIdx==1) {
            System.out.println("Stack 1 is:");
            for (int i = 0; i < Sta.top1+1; i++) {
                System.out.println(Sta.data[i]);
            }
        } else {
            System.out.println("Stack 2 is:");
            for (int i = MAXSIZE; i > Sta.top2-1; i--) {
                System.out.println(Sta.data[i-1]);
            }
        }
    }
}

Test code:

public class main {
    public static void main(String[] args) {
        ShareStack SS = new ShareStack(5);
        SS.push(1,2);
        SS.push(2,2);
        SS.push(3,2);
        SS.push("a",1);
        SS.push("b",1);
        SS.show(1);
        SS.show(2);
        System.out.println("--------------------");
        System.out.println("Delete element in 1:" + SS.pop(1));
        System.out.println("Delete 2 elements:" + SS.pop(2));
        System.out.println("--------------------");
        SS.show(1);
        SS.show(2);

    }
}

Chain storage structure of stack


The top of the stack is placed at the head of the chain list, and the chain stack is basically not full. For an empty stack, the original definition of the chain list is that the head pointer points to null, so the null of the chain stack is actually when top=NULL.

Structure code of chain stack:

typedef struct StackNode
{
    SElemType data;
    struct StackNode *next;
}StackNode, *LinkStackPtr;

typedef struct LinkStack
{
    LinkStackPtr top;
    int count;
}LinkStack;

push operation:
This is the opposite of the previous linked list. The next of each node points to the following, which is the previous element, because the linked list is first in first out.
The new node with element value e is s:

Status Push(LinkStack *S, SElemType e)
{
    LinkStackPrt s = (LinkStackPtr) malloc(sizeof(StackNode));
    s->data = e;
    s->next = S->top; // Assign the current stack element to the immediate successor of the new node
    S->top = s;    // The new node is called the top
    S->count++;
    return OK:
}

pop operation:

// Delete the stack top element of S and return the value. If the stack is empty, return ERROR
Status Pop(LinkStack *S, SElemType *e)
{
    LinkStackPtr p;
    if (StackEmpty(*S))
        return ERROR;
    *e = S->top->data;
    p = S->top;    //Get node address to release
    S->top = S->top->netx;    // Pointer down
    free(p);
    S->count--;
    return OK;
}

If the element change of the stack is unpredictable, it is better to use chain stack; if the change is within the controllable range, it is recommended to use sequence stack.

JAVA implementation chain stack

Chain stack class:

class StackNode{
    // Contains pointers and content to the previous
    public Object data;
    public StackNode next;

    public StackNode() {
        data = null;
        next = null;
    }
}



public class LinkStack {
    private int count;
    private StackNode top;

    public LinkStack() {
        count = 0;
        top = new StackNode();
    }

    public void push(Object e){
        // Set up something new first
        StackNode SN = new StackNode();
        SN.data = e;
        SN.next = top;  // Point to the front
        // Upgrade top
        top = SN;
        count++;
    }

    public Object pop(){
        if (count==0)
            throw new IndexOutOfBoundsException("No content to delete");
        Object data = top.data;
        top = top.next;
        count--;
        return data;
    }

    public void show(){
        StackNode sn = top;
        for (int i = 0; i < count; i++) {
            System.out.println(sn.data);
            sn = sn.next;
        }
    }
}

Test code:

public class main {
    public static void main(String[] args) {
        LinkStack LS = new LinkStack();
        LS.push(1);
        LS.push(2);
        LS.push(3);
        System.out.println("show:");
        LS.show();
        System.out.println("Delete:" + LS.pop());
        System.out.println("show:");
        LS.show();
    }
}

Application of stack

Function of stack:
It simplifies the problem of program design, divides different levels of concern, reduces the scope of thinking, and focuses more on the core of the problem we want to solve. In the case of arrays, we should also concentrate on the details of array subscripts.

recursion

Recursion definition: it is called recursion function that directly calls itself or indirectly calls its own function through a series of call statements.

Relationship with stack: imagine that recursion will be executed back in reverse order at the end of execution, so the compiler uses stack to implement recursion. When the function is called before, the local variables, parameter values and return addresses of the function are pushed into the stack; when the function is returned, these are popped up again.

Fibonacci sequence realization

Definition of the question: two months old rabbits can have little rabbits. A pair of rabbits can have a pair of rabbits every month. How many are there in a year?

Recursive Code:

int Fbi(int i)
{
    if (i<2)
        return i==0 ? 0 : 1;
    return Fbi(i-1) + Fbi(i-2);
}

int main()
{
    int i;
    for (int i=0; i<40; i++)
        print("%d", Fbi(i));
    return 0;
}

Evaluation of four operation expressions

Skip first

queue

Definition: a queue is a linear table that only allows insertion at one end and deletion at the other.
Queue is a first in first out (FIFO) linear table. The section allowed to be inserted is called the end of the team, and the one allowed to be deleted is called the head of the team.

Abstract data type of the queue:

Circular queue

Source:
If there is a common knowledge queue, there is a problem in using it. Here is a method to move every time you enter or leave, but it will be troublesome to move every time:

If the method of not moving is used, there should be two pointers, pointing to the head and tail of the team respectively, and moving the pointer every time when entering or leaving. Then if the total number of inserts exceeds the limited number, there will still be problems:

Outlet a1,a2a_1,a_2a1, a2 reentry a5a_5a5​:

This kind of situation is called false overflow when there are still empty bits (0 and 1), so we use the method of end-to-end queue to solve the false overflow.

New question: what about the overlap of real and front? There are two ways: one is to set a flag; the other is to keep a space and not let it be full. Method 2 is as follows:

Method 2 Correlation:

  1. The condition of full queue is: (rear + 1)% queuesize = = front
  2. Queue length calculation formula: (Rear - front + queuesize)% queuesize

Circular queue structure code:

typedef int QElemType;
typedef struct
{
    QElemType data[MAXSIZE];
    int front;
    int rear;
}SqQueue;

Loop queue initialization code:

Status InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
    return OK;
}

Circular queue queuing operation:

Status EnQueue(SqQueue *Q, QElemType e)
{
    if ( (Q->rear+1) % MAXSIZE == Q->front)    // Judge full
        return ERROR;
    Q->data[Q->rear] = e;    // Assign to end of team
    Q->rear = (Q->rear + 1) % MAXSIZE;    // Move backward to judge whether it is out of bounds
    return OK;
}

Loop queue out operation:

Status DeQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)    // Judge whether it is empty
        return ERROR;
    *e = Q->data[Q->front];    // Get team element
    Q->front = (Q->front + 1) % MAXSIZE;
    return OK;
}

Chain queue

Chain queue: the chain storage structure of a queue, in fact, is a single chain table of a linear table, but it can only be tail in and head out. We call it chain queue for short.

Generally, the queue head pointer points to the head node of the chain queue, while the queue tail pointer points to the terminal node. When the queue is empty, it points to the head node:

Structure of chain queue:

typedef int QElemType;

// Node structure
typedef struct QNode
{
    QElemType data;
    struct QNode *next;
}QNode, *QueuePtr;

// Chain structure of queues
typedef struct
{
    QueuePtr front, rear;    // Head tail pointer
}LinkQueue;

There are two kinds of constraints: one is that there is a next guide between elements, the other is that there is a head end pointer constraint range, but this time it is infinite growth, and there is no need to judge the cycle.

Queue operation of chain queue:
Is to insert a node at the end of the list

Status EnQueue(LinkQueue *Q, QElemType e)
{
    QueuePtr s = (QueuePtr) malloc(sizeof(QNode);
    if (!s)    // Judge whether the allocation is successful
        exit(OVERFLOW);
    s->data = e;
    s-next = NULL;
    Q->rear->next = s;
    Q->rear = s;
    return OK;
}

Outbound operation of chain queue:
It means that the successor node of the head node is out of the queue, and the successor direction of the head node is changed to the successor node. If there is only one element left except the head node, then the RER needs to point to the head node.

Status DeQueue(LinkQueue *Q, QElemType *e)
{
    QueuePrt p;
    if (Q->front == Q-rear)
        return ERROR;
    p = Q->front->next;
    *e = p->data;    // Get deleted elements
    Q->front->next = p->next;    // Point to the node behind

    if (Q->rear == p)    // If there is only one and it is deleted, the rear points to the head node
        Q->rear = Q->front;
    free(p);
    return OK;
}

The circular queue will apply for space in advance and will not be released during use. For the chain queue, it is often necessary to apply for and release. Therefore, it is recommended to use the circular queue when the maximum length of the queue can be determined.

Posted by ts2000abc on Sun, 21 Jun 2020 04:21:10 -0700