Chapter 4 stacks and queues

Chapter 4 stacks and queues

Stack table is defined linear only insertion and deletion operations in the trailer.

Queue insertion operation is only allowed at one end while the other end of the linear table delete operation.

Definitions 4.2 stack

4.2.1 the definition of the stack

Stack (Stack) is defined to make linear form and delete operations for the insertion end of the table.

Allow insertion and deletion of one end of the stack is called, and the other end is called bottom of the stack, the stack does not contain any data elements called empty stack. Also known LIFO stack (Last In First Out) linear form, referred LIFO structure.

Stack insert operation, called into the stack, also known as push, push.

Stack deletion, called the play, and some called popping.

4.2.2 push pop variant

1,2,3 turn into the stack, which will be the order of the stack

  1. Intake, feed 2, feed 3, 3, 2, 1
  2. Intake, 1, 2 inlet, 2, 3 into, 3
  3. Intake, feed 2, 2, 1, 3 inlet, 3
  4. Intake, 1, 2 enter, into the 3, 3, 2
  5. Intake, feed 2, 2, 3 into, 3, 1

4.3 Stack abstract data types

ADT 栈(stack)
Data
    同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
    InitStack(*S):初始化操作,建立一个空栈S。
    DestoryStack(*S):若栈存在,则销毁它。
    ClearStack(*S):将栈清空。
    StackEmpty(S):若栈为空,返回true,否则返回false。
    GetTop(S,*e):若栈存在且非空,用e返回S的栈顶元素。
    Push(*S, e):若栈S存在,插入新元素e到栈S中并成为栈顶元素。
    Pop(*S,*e):删除栈S中栈顶元素,并用e返回其值。
    StackLength(S):返回栈S的元素个数。
endADT

Sequential storage stack structure and realization 4.4

4.4.1 Stack sequential storage structure

Stack structure definition:

typedef int SElemType;          //SElemType类型根据实际情况而定,这里假设为int
typedef struct
{
    SElemType data[MAXSIZE];
    int top;                    //用于栈顶指针
}SqStack;

Stack ordinary circumstances, an empty stack and stack full situation:

Figure 4-4-1

4.4.2 stack sequential storage structure - onto the stack.

For insertion of the stack, i.e. the stack into operation:

Figure 4-4-3

So the stack is push

//插入元素e为新的栈顶元素
Status Push(SqStack *S, SElemType e)
{
    if(S->top == MAXSIZE - 1)       //栈满
    {
        return ERROR;
    }
    S->top++;                       //栈顶指针增加1
    S->data[S->top]=e;              //将新插入元素赋值给栈顶空间
}

4.4.3 sequential storage structure stack - the stack operation

Operating the stack pop, the following code:

//若栈不空,则删除S的栈顶元素,并用e返回其值,并返回OK,否则返回ERROR
Status Pop(SqStack *S, SElemType *e)
{
    if(S->top == -1)
        return ERROR;
    *e = S->data[S->top];
    S->top--;
    return OK;
}

4.5 stack two shared space

Two shared space stack structure of the code:

//两栈共享空间结构
typedef struct
{
    SElemType data[MAXSIZE];
    int top1;   //栈1 栈顶指针
    int top2;   //栈2 栈顶指针
}SqDoubleStack;

The method for push stack two shared space, apart from the element to be inserted into the parameter values, but also need to determine the stack 1 is a stack or stack number of parameters stackNumber 2.

Status Push(SqDoubleStack *S, SElemType e, int stackNumber)
{
    if (S->top1 + 1 == S->top2)         //栈已满,不能再push元素
        return ERROR;
    if (stackNumber == 1)               
        S->data[++S->top1] = e;         //若栈1,则先top1+1后给数组元素赋值
    else if (stackNumber == 2)
        S->data[--S->top2] = e;         //若栈2,则先top2-1后给数组元素赋值
    return OK;
}

Method stack pop two shared space, the parameter is judged stack 1, stack parameters of stackNumber 2

Satatus Pop(SqDoubleStack *S, SElemType *e, int stackNumber)
{
    if (stackNUmber == 1)
    {
         if (S->top1 == -1)
             return ERROR;          //说明栈1已经是空栈,溢出
        *e =S->data[S->top1--];     //将栈1的栈顶元素出栈
    }
    else if (stackNumber == 2)
    {
        if (S->top2 == MAXSIZE)
            return ERROR;           //说明栈2已经是空栈,溢出
        *e = S->data[S->top2++];    //将栈2的栈顶元素出栈
    }
    return OK;
}

4.6 Storage Structure and realization of the stack

4.6.1 Stack Storage Structure

Storage Structure of the stack, called the link stack.

Figure 4-6-1

Link stack structure of the code:

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

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

Storage Structure 4.6.2 stack - onto the stack.

For the link stack into the stack push operation, assuming that the new node element value of e is s, top of stack pointer

Figure 4-6-2

//插入元素e为新的栈顶元素
Status Push(LinkStack *S, SElemType e)
{
    LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
    s->data = e;
    s->next = S->top;               //把当前的栈顶元素赋值给新结点的直接后继
    S->top = s;                     //将新的结点s赋值给栈顶指针
    S->count++;
    return OK;                      
}

Storage Structure 4.6.3 stack - the stack operation

Figure 4-6-3

//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR
Status Pop(LinkStack *S, SElemType *e)
{
    LinkStackPtr p;
    if(StackEmpty(*S))
        return ERROR;
    *e = S->top->data;
    p=S->top;                   //将栈顶结点赋值给p
    S->top = S->top->next;      //使得栈顶指针下移一位,指向后一结点
    free(p);
    S->count--;
    return OK;
}

The link stack and push the stack into the stack pop operations are simple, without any cyclic operations are time complexity O (1).

4.7 stack effect

4.8 application stack - recursion

4.8.1 Fibonacci realization of Number of

1, 1, ... constitute a series, in front of and adjacent to two, constitute the last one, called the Fibonacci number.

official:

Figure 4-8-1

打印前4位的斐波那契数列数,代码

int main()
{
    int i;
    int a[40];
    a[0] = 0;
    a[1] = 1;
    printf("%d", a[0]);
    printf("%d", a[1]);
    for( i = 2; i < 40; i++)
    {
        a[i] = a[i - 1] + a[i - 2];
        printf("%d ", a[i]);
    }
    return 0;
}

递归实现:

//斐波那契的递归函数
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++)
        printf("%d", Fbi(i));
    return 0;
}

模拟代码中的Fbi(i)函数当i=5的执行过程

Figure 4-8-3

4.8.2 递归的定义

把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,称为递归函数。

递归定义必须至少有一个条件,满足递归不再进行,即不再引用自身而是返回值退出。

迭代和递归的区别,迭代使用的是循环结构,递归使用的是选择结构。

4.9 栈的应用-四则运算表达式求值

4.9.1 后缀(逆波兰)表示法定义

一种不需要括号的后缀表达法,我们也把它称为逆波兰表示。

例如"9 + ( 3 - 1) x 3 + 10 / 2 "用后缀表示法表示为"9 3 1 - 3 * + 10 2 / +"

4.9.2 后缀表达式计算结果

后缀表达式: 9 3 1 - 3 * + 10 2 / +

规则:从左到右遍历表达式的每个数字和符号,遇到数字就进栈,遇到符号就将栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

  1. 初始化一个空栈。此战用来对要运算的数字进出使用。

  2. 后缀表达式中前三个都是数字,所以9、3、1进栈,如图4-9-1

    Figure 4-9-1

  3. 接下来是‘-’,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈,如图4-9-2的左图所示。

  4. 接着是数字3进栈,如图4-9-2的右图所示。

    Figure 4-9-2

  5. 后面是"*",也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈,如果4-9-3的左图所示。

  6. 下面是'+',所以栈中6和9出栈,9与6相加,得到15,将15进栈,如图4-9-3的右图所示。

    Figure 4-9-3

  7. 接着是10与2两数字进栈,如图4-9-4左图所示。

  8. 接下来是符号'/',因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈,如如图4-9-4的右图所示。

    Figure 4-9-4

  9. 最后一个符号'+',所以15与5出栈并相加,得到20,将20进栈,如果4-9-5的左图所示。

  10. 结果20出栈,栈变为空,如图4-9-5的右图所示。

    Figure 4-9-5

    4.9.3 中缀表达式转后缀表达式

    我们平时所用的标准四则运算表达式,即"9 + ( 3 - 1) x 3 + 10 / 2"叫作中缀表达式。

    中缀表达式"9 + (3 -1) x 3 + 10 / 2"转化为后缀表达式 "9 3 1 - 3 * + 10 2 / +"。

    规则:

    从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;如是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。

    1. 初始化一个空栈,用来对符号进出栈使用。如图4-9-6的左图所示。

      Figure 4-9-6

    2. 第一个字符数字是9,输出9,后面是符号"+",进栈。如图4-9-6的右图所示。

    3. 第三个字符是"(",依然是符号,因其只是左括号,还未配对,故进栈。如图4-9-7的左图所示。

    4. 第四个字符是数字3,输出,总表达式9 3,接着是"-",进栈。如图4-9-7的右图所示。

    Figure 4-9-7

    1. 接下来是数字1,输出,总表达式为9 3 1,后面符号")",此时,我们需要去匹配此前的"(",所以栈顶依次出栈,并输出,直到"("出栈为止。此时左括号上方只有"-",因此输出"-"。总输出表达式为9 3 1 -。如图4-9-8的左图所示。

    2. 紧接着是符号"x",因为此时的栈顶符号为"+"号,优先级低于"X",因此不输出,"*"进栈。接着数字3,输出,总表达式为9 3 1 - 3。如图4-9-8的右图所示。

    Figure 4-9-8

    1. 之后是符号"+",此时当前栈顶元素""比这个"+"的优先级更高,因此栈中元素出栈并输出(没有比"+"更低的优先级,所以全部出栈),总输出表达式为9 3 1 - 3 +。然后将当前这个符号"+"进栈,也就是说,前6张图的栈底的"+"是指中缀表达式中开头的9后面那个"+",而图4-9-9左图中的栈底(也是栈顶)的"+"是指"9 + (3 - 1) x 3 +"中的最后一个"+"。

    2. 紧接着数字10,输出,总表达式变为9 3 1 - 3 * + 10。后是符号"/",所以"/"进栈。如图4-9-9的右图所示。

    Figure 4-9-9

    1. 最后一个数字2,输出,总的表达式为9 3 1 - 3 * + 10 2。如图4-9-10的左图所示。

    2. 因已到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为9 3 1 - 3 * + 10 2 / +。如4-9-10的右图所示。

      Figure 4-9-10

让计算机具有处理我们通常的标准(中缀)表达式的能力,最重要的两步:

  1. 将中缀表达式转化为后缀表达式(栈用来进出运算的符号)。
  2. 将后缀表达式进行运算得结果(栈用来进出运算得数字)。

4.10 队列得定义

队列是只允许在一端进行插入操作,而在另一端进行删除操作得线性表。

队列是一种先进先出(First In First Out)得线性表,简称FIFO。允许插入得一段称为队尾,允许删除得一端称为队头,队列数据插入只能在队尾进行,删除数据只能在队头进行。

队列结构如图4-10-1所示。

Figure 4-10-1

4.11 队列的抽象数据类型

ADT 队列(Queue)
Data
    同线性表,元素具有相同类型,相邻元素具有前驱和后继的关系。
Operation
    InitQueue(* Q):初始化操作,建立一个空队列Q。
    DestroyQueue(* Q):若队列存在, 则销毁它。
    ClearQueue(*Q):将队列Q清空。
    QueueEmpty(Q):若队列Q为空,返回为true,否则返回为false。
    GetHead(Q, *e):若队列Q存在且非空,用e返回队列Q的队列头元素。
    EnQueue(*Q, e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素。
    DeQueue(*Q, *e):删除队列Q中队头元素,并用e返回其值。
    QueueLength(Q):返回队列Q的元素个数。
endADT

4.12 循环队列

Table linear sequential storage structure and chain store, the stack is a linear table, it is stored in two ways. Also, as a special queue linear form, also exist two storage.

4.12.1 queue stored sequentially inadequate

Sequential storage queue, as is the FIFO, as required each time to remove the index 0, to migrate back sequentially, the presence of inefficiency.

4.12.2 cycle definition queue

We call this the head and tail of the queue sequentially storing contact circular queue structure is referred to.

Calculating queue length general formula:

(rear - front + QueueSize) % QueueSize

typedef int QElemType; //QElemType类型根据实际情况而定,这里假设为int
//循环队列的顺序存储结构
typedef struct
{
    QElemType data[MAXSIZE];
    int front;                  //头指针
    int rear;                   //尾指针
}SqQueue;

Circular queue initialization code as follows:

//初始化一个空队列
Status InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
    return OK;
}

Circular queues request queue length code is as follows:

//返回Q的元素个数,也就是队列的当前长度
int QueueLength(SqQueue Q)
{
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

Circular queue queues operation code as follows:

//若队列未满,则插入元素e为新的队尾元素
Status EnQueue(SqQueue *Q, QElemType e)
{
    if ((Q->rear + 1) % MAXSIZE == Q->front)//队列满的判断
        return ERROR;
    Q->data[Q->rear] = e;                   //将e元素赋值给队尾         
    Q->rear = (Q->rear + 1) % MAXSIZE;      //rear指针向后移一个位置,若到最后则跳转到数组头部
    return OK;
}

A circular queue queue operation code as follows:

//若队列不空,则删除Q中队头元素,用e返回其值
Status DeQueue(SqQueue *Q, QElemType *e)
{
    if (Q->front == Q->rear)                //队列为空的判断
        return ERROR;
    *e = Q->data[Q->front];                 
    Q->front = (Q->front + 1) % MAXSIZE;    //front指针向后移一个位置,若到最后则转到数组头部
}

Storage Structure and queues implemented 4.13

Storage Structure queue, in fact, single-chain linear form, but it can only head out into the end of it, we call it the chain queue.

Normal chain queue:

Figure 4-13-1

When the queue is empty, and the rear point Fron the head node, as shown in FIG 4-13-2

Figure 4-13-2

Chain configuration queue is:

typedef int QElemType;          //QElemType类型根据实际情况而定,这里假设为int

typedef struct QNode            //结点结构
{
    QElemTYpe data;
    struct QNode *next;
} QNode, *QueuePtr;

typedef struct                  //队列的链表结构
{
    QueuePtr front, rear;       //队头、队尾指针
}LinkQueue;

Storage Structure queue 4.13.1 - enqueue operation

Enqueue operation when, in fact, the insertion node at the tail of the linked list, as shown in FIG 4-13-3.

Figure 4-13-3

Code is as follows:

//插入元素e为Q的新的队尾元素
Status EnQueue(LinkQueue *Q, QElemType e)
{
    QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
    if(!s)
        exist(OVERFLOW);
    s->data = e;
    s->next = NULL;
    Q->rear->next = s;  //把拥有元素e新结点s赋值给队尾结点的后继
    Q->rear = s;        //把当前的s设置为队尾结点,rear指向s
    return OK;
}

4.13.2 queue Storage Structure - dequeue

When the dequeue operation, successor node is the head node dequeued, the head node to the subsequent node behind it, only if the list element in addition to a first node, the need rear head junction point point, as shown in FIG 4-13-4.

Figure 4-13-4

code show as below:

//若队列不空,删除Q的对头元素,用e返回其值,并返回OK,否则返回ERROR
Status DeQueue(LinkQueue *Q, QElemType *e)
{
    QueuePtr p;
    if(Q->front == Q->rear)
        return ERROR;
    p = Q->front->next;         //将欲删除的队头结点暂存给p
    *e = p->data;               //将欲删除的队头结点的值赋值给e
    Q->front->next = p->next;   //将原队头结点后继p->next赋值给头结点后继
    if(Q->rear == p)
        Q->rear = Q->front;
    free(p);
    return OK;
}

Summary: The case may determine the maximum queue length, is recommended when using circular queue, can not predict the length of the queue, the queue with the chain.

Guess you like

Origin www.cnblogs.com/spring-1991/p/11961400.html
Recommended