Implementation of stack and queue

Stack

Concept and structure of stack

Stack: a special linear table that allows insertion and deletion of elements only at a fixed end. One end for data insertion and deletion is called the top of the stack, and the other end is called the bottom of the stack. The data elements in the stack follow the principle of Last In First Out LIFO (Last In First Out).

Generally, the open end of the stack is called the top of the stack; Accordingly, the sealing end is called the bottom of the stack. Therefore, the stack top element refers to the element closest to the stack top.

Stack pressing: the stack insertion operation is called stack entering / stack pressing / stack entering, and the input data is at the top of the stack.

Stack out: stack deletion is called stack out. The output data is also at the top of the stack.

Implementation of stack

Stack can generally be implemented by array or linked list. Relatively speaking, the structure of array is better. Because the cost of inserting data on the tail of the array is relatively small. Let's work together to realize the following operations of dynamically opening up the storage space stack.

//Stack initialization
void InitStack(S* ps);
​
//Stack
void PushStack(S* ps, StackData x);
​
//Out of stack
void PopStack(S* ps);
​
//Empty
void ClearStack(S* ps);

Stack structure

typedef int StackData;
​
typedef struct Stack
{
    StackData* a;
    int size;//Number of stacked data
    int capacity;//capacity
}S;

Initialization and emptying of stack

The initialization and emptying operations of the stack are relatively simple, because there is no pressed data during initialization. You can set both size and capacity to 0 and a to NULL; When emptying, release the pointer and point to NULL. At the same time, set size and capacity to 0.

//Stack initialization
void InitStack(S* ps)
{
    ps->a = NULL;
    ps->size = ps->capacity = 0;
    printf("Initialization succeeded.\n");
}
​
//empty
void ClearStack(S* ps)
{
    free(ps->a);
    ps->a = NULL;
    ps->size = ps->capacity = 0;
    printf("The stack has been emptied.\n");
}

Stack in and stack out

For example, putting elements 1, 2, 3 and 4 on the stack in turn is equivalent to adding each element to the stack in turn by header insertion.

For the out of stack operation, if you want to take element 3 out of the stack, according to the principle of "first in, then out", you must first take element 4 out of the stack, that is, remove it from the stack, and then element 3 can be out of the stack:

The following code is used to realize the above operations:

//Push 
void PushStack(S* ps, StackData x)
{
    StackCheakCapacity(ps);
    ps->a[ps->size] = x;
    ps->size++;
    printf("Stack successfully.\n");
}
​
//Out of stack
void PopStack(S* ps)
{
    if (ps->size == 0)
    {
        printf("Empty stack cannot be ejected.\n");
        return;
    }
    printf("Pop up elements are:%d\n", ps->a[--ps->size]);
}

It should be noted that both capacity and size are 0 during initialization, and then the stack may be full due to size=capacity. Here, we might as well check the capacity every time we insert it. If the stack is full, we will expand it. Generally, we will double it:

//Check whether the capacity is enough. If not, expand the capacity to twice.
void StackCheakCapacity(S* ps)
{
​
    if (ps->size == ps->capacity)//When it is full, it will be expanded
    {
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        StackData* tmp = (StackData*)realloc(ps->a, newcapacity * sizeof(StackData));
        if (tmp == NULL)
        {
            printf("realloc fail\n");
            exit(-1);
        }
        else
        {
            ps->a = tmp;
            ps->capacity = newcapacity;
        }
    }
​
}

Another small detail in this code is the definition of newcapacity. When the capacity value is not 0, you can directly start realloc operation to open up twice the capacity space. However, if the capacity is equal to 0, its double or 0 is equivalent to no open space. Therefore, if the capacity is 0, we give the initial value of 4.

queue

Concept and structure of queue

Queue, like stack, is also a linear storage structure with strict requirements for data "storage" and "retrieval". Different from stack structure, both ends of queue are "open", which requires that data can only enter from one end and exit from the other end. Queue has the nature of first in first out FIFO(First In First Out).

Enter queue: the end of the queue at which the insertion operation is performed is called the end of the queue

Out of queue: the end for deletion is called the queue head.

Implementation of queue

The queue can also be implemented in the structure of array and linked list. It is better to use the structure of linked list, because if the structure of array is used, the efficiency will be relatively low. Let's implement the following operations to dynamically open up the storage space queue.

//Queue initialization
void QueueInit(Queue* pq);
//Queue destruction
void QueueDestroy(Queue* pq);
//Join the team
void QueuePush(Queue* pq, QDataType x);
//Out of the team
void QueuePop(Queue* pq);

Queue structure

typedef struct Queue
{
    QueueNode* head;
    QueueNode* tail;
}Queue;

Initialization and destruction of queues

It is similar to the initialization and destruction of the stack. Since the queue operation has not yet been performed, you may wish to point to NULL for both head and tail; When destroying, release the pointer and point to NULL.

//initialization
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->head = NULL;
    pq->tail = NULL;
}
​
//Destroy
void QueueDestroy(Queue* pq)
{
    assert(pq);
    QueueNode* cur = pq->head;
    while (cur != NULL)
    {
        QueueNode* next = cur->next;
        free(cur);
        cur = next;
    }
​
    pq->head = pq->tail = NULL;
​
}

Join and leave the team

 

//Join the team
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
    newnode->data = x;
    newnode->next = NULL;
​
    if (pq->head == NULL)
    {
        pq->head = pq->tail = newnode;
    }
    else
    {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }
​
}
​
//Out of the team
void QueuePop(Queue* pq)
{
    assert(pq);
    //if (pq->head == NULL)
    //  return;
    assert(!QueueEmpty(pq));
​
    QueueNode* next = pq->head->next;
    free(pq->head);
    pq->head = next;
    if (pq->head == NULL)
    {
        pq->tail = NULL;
    }
​
}

Keywords: data structure

Added by powerpants on Wed, 19 Jan 2022 21:59:42 +0200