《数据结构》自学考试 课程代码02331 2012版 第03章 栈和队列 例题集和编程练习

本文详细讲解了顺序栈、链式栈和循环队列的原理与操作,包括栈的空栈、满栈判断,队列的空队、满队判断,以及它们在回文判定、进制转换、表达式处理等实际问题中的应用。通过实例演示和编程练习,深入理解这两种数据结构的运用技巧。
摘要由CSDN通过智能技术生成

  • OS: Mac Catalina 10.15.4 
  • Hardware: Intel Core i9/16G 2667MHz DDR4
  • 编译器版本:Mac Xcode 11.6 

第03章 栈和队列


目录

例题

例题01 顺序栈的结构

例题02 置顺序栈为空栈

例题03 判断顺序栈是否为空栈

例题04 判断顺序栈是否为满栈

例题05 顺序栈入栈

例题06 顺序栈出栈

例题07 顺序栈取栈顶元素

例题08 链式栈的结构

例题09 链式栈判断是否为空

例题10 链式栈入栈

例题11 链式栈出栈

例题12 链式栈取栈顶元素

例题13 使用链式栈做圆括号匹配判定

例题14 使用顺序栈做回文判定

例题15 使用顺序栈做进制转换

例题16 栈的递归问题求解1,阶乘

例题17  栈的递归问题求解2,求函数

例题18 循环顺序队列结构定义

例题19 循环顺序队列置空

例题20 循环顺序队列判断是否为空

例题21 循环顺序队列判断是否队满

例题22 循环顺序队列入队

例题23 循环顺序队列取队头

例题24 循环顺序队列出队

例题25 带头结点的单向链式队列结构定义

例题26 带头结点的单向链式队构建

例题27 带头结点的单向链式队列判断是否为空队

例题28 带头结点的单向链式队列入队

例题29 带头结点的单向链式队列取队头元素

例题30 带头结点的单向链式队列出队

例题31 带头结点的单向链式队列综合测试

例题32 单向循环链式队列结构定义

例题33 单向循环链式队列构建

例题34 单向循环链式队列判断是否为空

例题35 单向循环链式队列入队

例题36 单向循环链式队列取队头元素

例题37 单向循环链式队列出队

例题38 单向循环链式队列综合测试

例题39 中缀表达式转后缀表达式

编程练习

习题20

 习题21

习题22


例题

例题01 顺序栈的结构

#define StackSize 100               // 栈空间的大小应根据实际需要来定义,这里假设为100
typedef char DataType;              // DataType的类型可根据实际情况而定,这里假设为char
typedef unsigned int list_size;     // 定义栈大小的类型,这里定义的是无符号整型
typedef struct
{
    DataType data[StackSize];       // 数组data用来存放表结点
    list_size top;                  // 栈顶位置
}SeqStack;
SeqStack Stack;

例题02 置顺序栈为空栈

void InitStack(SeqStack *S)
{
    S->top = 0;
}

程序示例:

int main(void)
{
    SeqStack S;
    InitStack(&S);
    
    printf("顺序栈长度为:%d\n", S.top);
    
    return 0;
}

程序运行结果:

例题03 判断顺序栈是否为空栈

// 判断顺序栈是否为空栈
// 参数:
//      SeqStack *S:            顺序栈指针
// 返回:
//      bool:                   如果为空栈则返回true,否则返回false
bool IsEmpty(SeqStack *S)
{
    return S->top == 0;
}

例题04 判断顺序栈是否为满栈

// 判断顺序栈是否为满栈
// 参数:
//      SeqStack *S:            顺序栈指针
// 返回:
//      bool:                   如果为满栈则返回true,否则返回false
bool IsFull(SeqStack *S)
{
    return S->top == StackSize;
}

例题05 顺序栈入栈

// 顺序栈入栈
// 参数:
//      SeqStack *S:            顺序栈指针
//      DataType item:          入栈一个元素
// 返回:
//      void
void Push(SeqStack *S, DataType item)
{
    // 如果已经满栈,则提示并返回
    if (IsFull(S))
        printf("[Stock overflow]\n");
    else
    {
        S->data[S->top] = item;     // 向栈定压入一个元素
        S->top++;                   // 栈长度+1
    }
}

程序示例:

int main(void)
{
    SeqStack S;
    int i;
    InitStack(&S);
    if (IsEmpty(&S))
        printf("顺序栈是一个空栈.\n");
    for (i = 1; i <= 100; i++)
        Push(&S, (DataType)(96 + i));
    if (IsFull(&S))
        printf("顺序栈已经满栈.\n");
    
    printf("顺序栈长度为:%d\n", S.top);
    
    return 0;
}

程序运行结果:

例题06 顺序栈出栈

// 顺序栈出栈
// 参数:
//      SeqStack *S:            顺序栈指针
// 返回:
//      DataType:               返回栈顶元素,若栈为空则报错
DataType Pop(SeqStack *S)
{
    if (IsEmpty(S))
    {
        printf("[Stack underflow]");
        return (DataType)NULL;
    } else
        return S->data[--S->top];
}

示例程序:

int main(void)
{
    SeqStack S;
    int i;
    InitStack(&S);
    for (i = 1; i <= 5; i++)
        Push(&S, (DataType)(96 + i));
    printf("顺序栈出栈: ");
    for (i = 1; i <= 5; i++)
        printf("%c ", Pop(&S));
    printf("\n顺序栈长度为:%d\n", S.top);
    
    return 0;
}

程序执行结果:

例题07 顺序栈取栈顶元素

// 取栈顶元素
// 参数:
//      SeqStack *S:            顺序栈指针
// 返回:
//      DataType:               返回栈顶元素,若栈为空则报错
DataType GetTop(SeqStack *S)
{
    if (IsEmpty(S))
    {
        printf("[Stack underflow]");
        return (DataType)NULL;
    } else
        return S->data[S->top - 1];     // 返回栈顶元素
}

示例程序:

int main(void)
{
    SeqStack S;
    int i;
    DataType c;
    InitStack(&S);
    printf("入栈数据: ");
    for (i = 1; i <= 5; i++)
    {
        c = (DataType)(96 + i);
        printf("%c ", c);
        Push(&S, c);
    }
    printf("\n顺序栈出栈: ");
    for (i = 1; i <= 5; i++)
        printf("%c ", GetTop(&S));
    printf("\n顺序栈长度为:%d\n", S.top);
    
    return 0;
}

程序执行结果:

例题08 链式栈的结构

typedef int DataType;       // DataType的类型可根据实际情况而定,这里假设为int
typedef struct stacknode
{
    DataType data;
    struct stacknode *next; // 指向下一个结点的指针
}StackNode;
typedef StackNode *LinkStack;

例题09 链式栈判断是否为空

// 判断链式栈是否为空
// 参数:
//      LinkStack top:          链式栈栈顶指针
// 返回:
//      bool:                   如果为空,则表示已经到栈底为空栈返回true,否则返回false
bool isStackEmpty(LinkStack top)
{
    return top == NULL;
}

例题10 链式栈入栈

// 插入栈顶元素
// 参数:
//      LinkStack top:          链式栈栈顶指针
//      DataType x:             入栈的值
// 返回:
//      LinkStack:              新的栈顶指针
LinkStack Push(LinkStack top, DataType value)
{
    StackNode *p;
    p = (StackNode*)malloc(sizeof(StackNode));      // 申请新结点空间
    p->data = value;
    p->next = top;                                  // 将新结点*p插入到栈顶
    top = p;                                        // 使top指向新的栈顶
    return top;                                     // 返回新栈顶指针
}

例题11 链式栈出栈

// 出栈
// 参数:
//      LinkStack top:          链式栈栈顶指针
//      DataType *x:            退栈的栈顶元素值
// 返回:
//      LinkStack:              新的栈顶指针
LinkStack Pop(LinkStack top, DataType *value)
{
    StackNode *p = top;                             // 保存栈顶指针
    if (isStackEmpty(top))                          // 判断栈是否为空
    {
        printf("[stack empty]");
        return NULL;
    } else
    {
        *value = p->data;                           // 保存删除结点的值,并带回
        top = p->next;                              // 栈顶指针指向下一个结点
        free(p);                                    // 删除p指向的结点
        return top;                                   // 返回删除后的新的栈顶结点指针
    }
}

例题12 链式栈取栈顶元素

// 取栈顶元素
// 参数:
//      LinkStack top:          链式栈栈顶指针
// 返回:
//      DataType:               栈顶元素值
DataType GetTop(LinkStack top)
{
    if (isStackEmpty(top))                          // 判断栈是否为空
    {
        printf("[stack empty]");
        return (DataType)NULL;
    } else
        return top->data;                             // 返回栈顶结点值
}

程序实例:

int main(void)
{
    LinkStack L = NULL;
    int i;
    DataType v;
    if (isStackEmpty(L))
        printf("链式栈是个空栈\n");
    printf("入栈数据: ");
    for (i = 1; i <= 5; i++)
    {
        printf("%d ", i);
        L = Push(L, (DataType)i);
    }
    printf("\n栈顶数据为: %d", GetTop(L));
    printf("\n出栈数据: ");
    for(i = 1; i <= 5; i++)
    {
        L = Pop(L, &v);
        printf("%d ", v);
    }
    printf("\n");
    if (isStackEmpty(L))
        printf("链式栈是个空栈\n");
    
    return 0;
}

程序运行结果:

例题13 使用链式栈做圆括号匹配判定

bool isExpr()
{
    LinkStack S = NULL;             // 初始化栈
    DataType ch, x;
    ch = getchar();
    while (ch != '\n')
    {
        if (ch == '(')
            S = Push(S, ch);            // 遇到左括号进栈
        else
            if (ch == ')')
            {
                if (isStackEmpty(S))
                    return 0;
                else
                    S = Pop(S, &x);
            }
        ch = getchar();
    } // end of while
    return isStackEmpty(S);
}

示例程序:

int main(void)
{
    printf("输入表达式(按回车确认):");
    if (isExpr())
        printf("圆括号匹配.\n");
    else
        printf("圆括号不匹配.\n");
}

运行结果:

 

例题14 使用顺序栈做回文判定

bool symmetry(char str[])
{
    SeqStack S;
    int j, k, i = 0;
    InitStack(&S);
    while (str[i] != '\0')
        i++;                    // 求串的长度
    for (j = 0; j < i / 2; j++)
        Push(&S, str[j]);       // 前一半字符串入栈
    k = (i + 1) / 2;            // 后一半字符在串中的起始位置
    for (j = k; j < i; j++)     // 后一半字符与栈中字符比较
    {
        if (str[j] != Pop(&S))  // 有不相同字符,则不对称
            return false;
    }
    return true;                // 完全相同,则对称
}

程序实例:

int main(void)
{
    char str[100];
    printf("输入一个字符串(<=100个字符,按回车确认):");
    scanf("%s", str);
    if (symmetry(str))
        printf("回文\n");
    else
        printf("不是回文\n");
    return 0;
}

程序执行结果:

例题15 使用顺序栈做进制转换

// 将一个非负的十进制数N转换成任意的d进制数
// 参数:
//      unsigned int N:         非负的十进制数N
//      unsigned short d:       任意的d进制数
// 返回:
//      void
void conversion(unsigned int N, unsigned short d)
{
    SeqStack S;
    InitStack(&S);
    DataType val;
    
    // 以此将余数入栈
    while (N)
    {
        val = N % d;
        Push(&S, val);
        N = N / d;
    }
    // 如果栈为非空,则依次出栈
    while (!IsStackEmpty(&S))
    {
        val = Pop(&S);
        if (d == 16)    // 如果是转换为16进制,则10~15使用ABCDEF表示
        {
            if (val >= 10 && val <= 15)
                printf("%c", 65 + (val - 10));  // 大写字母A~F
        } else
            printf("%d", val);
    }
}

程序实例:

int main(void)
{
    unsigned int N = 11259375;//十进制
    printf("十进制非负整数: %u\n", N);
    printf("转换成 八进制 进制为: ");
    conversion(N, 8);
    printf("\n转换成 二进制 进制为: ");
    conversion(N, 2);
    printf("\n转换成 二进制 进制为: ");
    conversion(N, 16); printf("\n");
    return 0;
}

程序输出结果:

例题16 栈的递归问题求解1,阶乘

long double fact(unsigned int n)
{
    long double temp;
    if (n == 0)
        return 1;
    else
        temp = n * fact(n - 1);
    return temp;
}

int main(void)
{
    long double n;
    n = fact(25);
    printf("25! = %.0Lf\n", n);
}

程序输出结果:

注意:

  • 使用long double类型并不能处理26!。
  • 使用Mathematica可以计算超大的数据,比如100!,如下图:

例题17  栈的递归问题求解2,求函数

float fu(int n)
{
    if (n < 2)
        return (n + 1);
    else
        return fu(n / 2) * fu(n / 4);
}

int main(void)
{
    int n = 10;
    printf("fu() = %f\n", fu(n));
}

程序执行结果:

例题18 循环顺序队列结构定义

#define QueueSize 100
typedef char DataType;              // 假设数据为字符型
typedef unsigned int list_size;     // 队列长度类型
typedef struct
{
    DataType data[QueueSize];
    list_size front, rear;
    list_size length;
}CirQueue;

例题19 循环顺序队列置空

// 置空队列
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      void
void InitQueue(CirQueue *Q)
{
    Q->front = Q->rear = Q->length = 0;
}

例题20 循环顺序队列判断是否为空

// 判断队列是否为空队列
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      bool:                   如果为空队列,则返回true,否则返回false
bool IsQueueEmpty(CirQueue *Q)
{
    return Q->length == 0;
}

例题21 循环顺序队列判断是否队满

// 判断队列是否为满队列
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      bool:                   如果为满队列,则返回true,否则返回false
bool IsQueueFull(CirQueue *Q)
{
    return Q->length == QueueSize;
}

例题22 循环顺序队列入队

// 入队列,插入元素value为队列Q新的队尾元素
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      void
void EnQueue(CirQueue *Q, DataType value)
{
    if (IsQueueEmpty(Q))
        printf("[Queue overflow]");
    else
    {
        Q->data[Q->rear] = value;
        Q->rear = (Q->rear + 1) % QueueSize;    // 循环意义下的加+1
        Q->length++;
    }
}

例题23 循环顺序队列取队头

// 取队头元素值
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      DataType:               返回队列头值
DataType GetFront(CirQueue *Q)
{
    if (IsQueueEmpty(Q))
    {
        printf("[Queue empty]");
        return (DataType)NULL;
    } else
        return Q->data[Q->front];
}

例题24 循环顺序队列出队

// 出队列,删除Q的队头元素并返回其值
// 参数:
//      CirQueue *Q:            循环队列指针
// 返回:
//      DataType:               返回删除队头元素的值
DataType ExQueue(CirQueue *Q)
{
    DataType value;
    // 如果队列已经为空,则无法出队
    if (IsQueueEmpty(Q))
    {
        printf("[Queue empty]");
        return (DataType)NULL;
    } else
    {
        value = Q->data[Q->front];              // 保存待删元素的值
        Q->front = (Q->front + 1) % QueueSize;  // 头指针+1
        Q->length--;
        return value;
    }
}

测试程序:

int main(void)
{
    CirQueue Q;
    int i;
    DataType value;
    
    printf("开始初始化循环队列...\n");
    InitQueue(&Q);
    printf("初始化循环队列完成。队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
    printf("列表是否为空列表:%c  是否为满列表:%c\n",
           (IsQueueEmpty(&Q) ? 'Y' : 'N'),
           (IsQueueFull(&Q) ? 'Y' : 'N'));
    
    printf("------------\n");
    printf("开始入队5个元素...\n元素列表为:");
    for (i = 1; i <= 5; i++)
    {
        printf("%c", (64 + i));
        EnQueue(&Q, (DataType)(64 + i));
    }
    printf("\n队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
    printf("列表是否为空列表:%c  是否为满列表:%c\n",
           (IsQueueEmpty(&Q) ? 'Y' : 'N'),
           (IsQueueFull(&Q) ? 'Y' : 'N'));
    
    printf("------------\n");
    printf("出队3个元素...\n出队元素为:");
    for (i = 1; i <= 3; i++)
    {
        value = ExQueue(&Q);
        printf("%c", value);
    }
    printf("\n此时队列头的元素为:%c\n", GetFront(&Q));
    printf("队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
    printf("列表是否为空列表:%c  是否为满列表:%c\n",
           (IsQueueEmpty(&Q) ? 'Y' : 'N'),
           (IsQueueFull(&Q) ? 'Y' : 'N'));
    
    printf("------------\n");
    printf("开始入队2个元素...\n元素列表为:");
    for (i = 1; i <= 2; i++)
    {
        printf("%c", (69 + i));
        EnQueue(&Q, (DataType)(69 + i));
    }
    printf("\n此时队列头的元素为:%c\n", GetFront(&Q));
    printf("队列容量=%d,队列成员个数=%d\n", QueueSize, Q.length);
    printf("列表是否为空列表:%c  是否为满列表:%c\n",
           (IsQueueEmpty(&Q) ? 'Y' : 'N'),
           (IsQueueFull(&Q) ? 'Y' : 'N'));
    return 0;
}

程序输出结果:

 注意:

  • 这里使用的循环队列容量=5
  • 定义了length成员,用来记录元素个数

例题25 带头结点的单向链式队列结构定义

typedef char DataType;              // 假设数据为字符型

typedef struct qnode
{
    DataType data;
    struct qnode * next;
} QueueNode;                        // 链式队列结点类型

typedef struct
{
    QueueNode *front;               // 队头指针
    QueueNode *rear;                // 队尾指针
}LinkQueue;

例题26 带头结点的单向链式队构建

// 创建一个带头结点的单向链表
// 参数:
//      LinkQueue *Q    未分配空间的链式队列
// 返回:
//      void
void InitQueue(LinkQueue *Q)
{
    Q->front = (QueueNode *)malloc(sizeof(QueueNode));      // 申请头结点空间
    Q->rear = Q->front;                                     // 尾结点也指向头结点
    Q->rear->next = NULL;
}

例题27 带头结点的单向链式队列判断是否为空队

// 判断队列是否为空
// 参数:
//      LinkQueue *Q    带头结点的单向队列
// 返回:
//      bool            如果为空返回true否则返回false
bool IsQueueEmpty(LinkQueue *Q)
{
    return Q->rear == Q->front;                             // 头尾指针相等队列为空 
}

例题28 带头结点的单向链式队列入队

// 入队列
// 将元素item插入到链式队列的尾部
// 参数:
//      LinkQueue *Q    带头结点的单向队列
//      DataType        入队元素的数值
// 返回:
//      void
void EnQueue(LinkQueue *Q, DataType item)
{
    QueueNode *p = (QueueNode *)malloc(sizeof(QueueNode));  // 申请新结点
    p->data = item;
    p->next = NULL;
    Q->rear->next = p;  // *p链到原队尾结点之后
    Q->rear = p;        // 队尾指针指向新的队尾结点
}

例题29 带头结点的单向链式队列取队头元素

// 取队头元素
// 取链式队列的队头元素值
// 参数:
//      LinkQueue *Q    带头结点的单向队列
// 返回:
//      DataType        元素值
DataType GetFront(LinkQueue *Q)
{
    if (IsQueueEmpty(Q))
    {
        printf("[Queue underflow]");
        return (DataType)NULL;              // 出错返回NULL
    }
    else
        return Q->front->next->data;         // 返回原队头元素值
}

例题30 带头结点的单向链式队列出队

// 删除链式队列的头结点,并返回头结点的元素值
// 参数:
//      LinkQueue *Q    带头结点的单向队列
// 返回:
//      DataType        被删除的头结点的元素值
DataType DeQueue(LinkQueue *Q)
{
    QueueNode *p;
    if (IsQueueEmpty(Q))
    {
        printf("[Queue underflow]");
        return (DataType)NULL;              // 出错返回NULL
    }
    else
    {
        p = Q->front;                           // p指向头结点
        Q->front = Q->front->next;              // 头指针指向原队头结点
        free(p);                                // 删除释放原头结点
        return(Q->front->data);                 // 返回原队头结点的数据值
    }
}

例题31 带头结点的单向链式队列综合测试

int main(void)
{
    int i;
    QueueNode *p;
    
    LinkQueue Q;
    printf("初始化链式队列...\n");
    InitQueue(&Q);
    printf("初始化完成,队列是否为空: %s\n\n", IsQueueEmpty(&Q) ? "是" : "否");
    
    printf("开始在队列尾入队A~G...\n");
    for(i = 'A'; i <= 'G'; i++)
        EnQueue(&Q, i);
    printf("入队完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    p = Q.front->next;
    i = 1;
    if (p != NULL)
        printf("队头元素值为: %c\n", GetFront(&Q));
    printf("队列内容为: ");
    while (p != NULL)
    {
        printf("[%d]=%c ", i++, p->data);
        p = p->next;
    }
    
    printf("\n\n准备出队前3个元素...\n");
    for (i = 1; i <= 3; i++)
        DeQueue(&Q);
    printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    p = Q.front->next;
    i = 1;
    if (p != NULL)
        printf("队头元素值为: %c\n", GetFront(&Q));
    printf("队列内容为: ");
    while (p != NULL)
    {
        printf("[%d]=%c ", i++, p->data);
        p = p->next;
    }
    printf("\n\n删除剩余队列的所有元素...\n");
    p = Q.front->next;
    while (!IsQueueEmpty(&Q))
        DeQueue(&Q);
    printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    
    return 0;
}

程序运行结果:

例题32 单向循环链式队列结构定义

typedef char DataType;                      // 假设数据为字符型

typedef struct qnode
{
    DataType data;
    struct qnode * next;
} QueueNode;                                // 链式队列结点类型

typedef struct
{
    QueueNode *rear;                        // 队尾指针
}LinkQueue;

例题33 单向循环链式队列构建

// 创建一个带头结点的单向循环队列
// 参数:
//      LinkQueue *Q    未分配空间的链式队列
// 返回:
//      void
void InitQueue(LinkQueue *Q)
{
    Q->rear = (QueueNode *)malloc(sizeof(QueueNode));      // 申请头结点空间
    Q->rear->next = Q->rear;
}

例题34 单向循环链式队列判断是否为空

// 判断队列是否为空
// 参数:
//      LinkQueue *Q    带头结点的单向队列
// 返回:
//      bool            如果为空返回true否则返回false
bool IsQueueEmpty(LinkQueue *Q)
{
    return Q->rear->next == Q->rear;                         // 头尾指针相等队列为空
}

例题35 单向循环链式队列入队

// 入队列
// 将元素item插入到链式队列的尾部
// 参数:
//      LinkQueue *Q    带头结点的单向队列
//      DataType        入队元素的数值
// 返回:
//      void
void EnQueue(LinkQueue *Q, DataType item)
{
    QueueNode *p = (QueueNode *)malloc(sizeof(QueueNode));  // 申请新结点
    p->data = item;
    p->next = Q->rear->next;    // 新结点指向队列的头结点
    Q->rear->next = p;          // *p链到原队尾结点之后
    Q->rear = p;                // 队尾指针指向新的队尾结点
}

例题36 单向循环链式队列取队头元素

// 取队头元素
// 取链式队列的队头元素值
// 参数:
//      LinkQueue *Q    带头结点的单向循环队列
// 返回:
//      DataType        元素值
DataType GetFront(LinkQueue *Q)
{
    if (IsQueueEmpty(Q))
    {
        printf("[Queue underflow]");
        return (DataType)NULL;              // 出错返回NULL
    }
    else
        return Q->rear->next->next->data;   // 返回原队头元素值
}

例题37 单向循环链式队列出队

// 删除链式队列的头结点,并返回头结点的元素值
// 参数:
//      LinkQueue *Q    带头结点的单向队列
// 返回:
//      DataType        被删除的头结点的元素值
DataType DeQueue(LinkQueue *Q)
{
    QueueNode *h;
    if (IsQueueEmpty(Q))
    {
        printf("[Queue underflow]");
        return (DataType)NULL;              // 出错返回NULL
    }
    else
    {
        h = Q->rear->next;                  // p指向头结点
        Q->rear->next = h->next;            // 头指针指向原队头结点
        free(h);                            // 删除释放原头结点
        return(Q->rear->next->data);        // 返回原队头结点的数据值
    }
}

例题38 单向循环链式队列综合测试

int main(void)
{
    int i;
    QueueNode *p;
    
    LinkQueue Q;
    printf("初始化链式队列...\n");
    InitQueue(&Q);
    printf("初始化完成,队列是否为空: %s\n\n", IsQueueEmpty(&Q) ? "是" : "否");
    
    printf("开始在队列尾入队A~G...\n");
    for(i = 'A'; i <= 'G'; i++)
        EnQueue(&Q, i);
    printf("入队完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    p = Q.rear->next->next;
    i = 1;
    if (!IsQueueEmpty(&Q))
        printf("队头元素值为: %c\n", GetFront(&Q));
    printf("队列内容为: ");
    while (p != Q.rear->next)
    {
        printf("[%d]=%c ", i++, p->data);
        p = p->next;
    }
    
    printf("\n\n准备出队前3个元素...\n");
    for (i = 1; i <= 3; i++)
        DeQueue(&Q);
    printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    p = Q.rear->next->next;
    i = 1;
    if (!IsQueueEmpty(&Q))
        printf("队头元素值为: %c\n", GetFront(&Q));
    printf("队列内容为: ");
    while (p != Q.rear->next)
    {
        printf("[%d]=%c ", i++, p->data);
        p = p->next;
    }
    printf("\n\n删除剩余队列的所有元素...\n");
    p = Q.rear->next->next;
    while (!IsQueueEmpty(&Q))
        DeQueue(&Q);
    printf("删除完成,队列是否为空: %s\n", IsQueueEmpty(&Q) ? "是" : "否");
    
    return 0;
}

程序测试结果:

例题39 中缀表达式转后缀表达式

#include <stdio.h>
#include "SeqStack.h"
#include "LinkQueue.h"

int Priority(DataType op);      // 操作符权限
void CTPostExp(LinkQueue *Q);   // 中缀表达式转后缀表达式
int CPostExp(LinkQueue *Q);     // 计算后缀表达式

int main(void)
{
    LinkQueue Q;
    QueueNode *p;
    
    InitQueue(&Q);
    printf("输入中缀表达式: ");
    //9-(2+4*7)/5+3#
    CTPostExp(&Q);
    printf("后缀表达式为: ");
    p = Q.front->next;
    while (p != NULL)
    {
        printf("%c", p->data);
        p = p->next;
    }
    printf("\n表达式计算结果为: %d\n", CPostExp(&Q));
    return 0;
}

// 操作符权限优先级
int Priority(DataType op)
{
    switch(op)
    {
        case '(':
        case '#': return 0;
        case '-':
        case '+': return 1;
        case '*':
        case '/': return 2;
    }
    
    return -1;
}

// 中缀表达式转后缀表达式
void CTPostExp(LinkQueue *Q)
{
    SeqStack S;                 // 运算符栈
    char c, t;
    InitStack(&S);              // 初始化栈
    Push(&S, '#');              // 压入栈底元素'#'
    do                          // 扫描中缀表达式
    {
        c = getchar();
        switch (c)
        {
            case ' ': break;    // 去除空格富
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                EnQueue(Q, c);
                break;
            case '(':
                Push(&S, c);
                break;
            case ')':
            case '#':
                do
                {
                    t = Pop(&S);
                    if (t != '(' && t != '#')
                        EnQueue(Q, t);
                }while (t != '(' && S.top != 0); break;
            case '+':
            case '-':
            case '*':
            case '/':
                while (Priority(c) <= Priority(GetTop(&S)))
                {
                    t = Pop(&S);
                    EnQueue(Q, t);
                }
                Push(&S, c);
                break;
        }
    }while (c != '#');          // 以'#'号结束表达式扫描
}

int CPostExp(LinkQueue *Q)
{
    SeqStack S;
    char ch;
    int x, y;
    InitStack(&S);
    while(!IsQueueEmpty(Q))
    {
        ch = DeQueue(Q);
        if (ch >= '0' && ch <= '9')
            Push(&S, ch - '0');
        else
        {
            y = Pop(&S);
            x = Pop(&S);
            switch(ch)
            {
                case '+': Push(&S, x + y); break;
                case '-': Push(&S, x - y); break;
                case '*': Push(&S, x * y); break;
                case '/': Push(&S, x / y); break;
            }
        }
    }
    return GetTop(&S);
}

输出结果:

编程练习

习题20

利用两个栈S1和S2模拟一个队列,如何用栈的运算来实现队列的插入和删除运算?试写出算法

typedef struct
{
    SeqStack stack;
}StackQueue;
typedef StackQueue *node;

void InitQueue(StackQueue *Q)
{
    InitStack(&Q->stack);
}

bool IsQueueEmpty(StackQueue *Q)
{
    return IsStackEmpty(&Q->stack);
}

void EnQueue(StackQueue *Q, DataType item)
{
    Push(&Q->stack, item);
}

DataType DeQueue(StackQueue *Q)
{
    SeqStack S;
    list_size p;
    DataType item;
    char c;
    
    if (IsStackEmpty(&Q->stack))
    {
        printf("[Stack underflow]");
        return (DataType)NULL;
    } else
    {
        InitStack(&S);
        p = Q->stack.top;
        while (p-- > 1)
        {
            c = Pop(&Q->stack);
            Push(&S, c);
        }
        item = Pop(&Q->stack);
        while (!IsStackEmpty(&S))
            Push(&Q->stack, Pop(&S));
    }
    return item;
}
int main(void)
{
    StackQueue Q;
    int i;
    char c;
    
    printf("开始初始化队列...\n");
    InitQueue(&Q);
    printf("初始化队列完成,开始向队列入队字母:A~G...\n");
    for(c = 'A'; c <= 'G'; c++)
        EnQueue(&Q, c);
    printf("入队完成,队列成员为: ");
    for(i = 0; i <= 'G' - 'A'; i++)
        printf("[%d]=%c ", i + 1, Q.stack.data[i]);
    printf("\n开始出队前3个...\n");
    for (i = 1; i <= 3; i++)
        printf("%c ", DeQueue(&Q));
    printf("\n出队完成,剩余队列成员为: ");
    for(i = 0; i <= 'G' - 'A' - 3; i++)
        printf("[%d]=%c ", i + 1, Q.stack.data[i]);
    printf("\n剩余队列全部出队...\n");
    while (!IsQueueEmpty(&Q))
        printf("%c ", DeQueue(&Q));
    printf("\n出队完成,队列成员为:%s\n", IsQueueEmpty(&Q) ? "空" : "非空");
    
    return 0;
}

程序执行结果:

 习题21

试设计一个算法,实现输入一个字符串并检查字符串中是否含有圆括号,当圆括号匹配时输出括号内的字符串,否则给出出错信息(提示:利用栈记录左括号出现后的字符)。

#include <stdio.h>
#include <stdbool.h>
#include "LinkQueue.h"

int main(void)
{
    char string[1024];
    int i = 0;
    char c;
    bool sign = false;
    LinkQueue Q;
    InitQueue(&Q);
    
    printf("输入一串字符串:");
    scanf("%s", string);
    do
    {
        c = string[i++];
        if (c == '(')
            sign = true;
        else if (c == ')')
        {
            sign = false;
            break;
        }
        else if (sign)
            EnQueue(&Q, (DataType)c);
    }while (c != '\0' || c != ')');
    
    printf("括号中的内容为:\n");
    while (!IsQueueEmpty(&Q))
        printf("%c", DeQueue(&Q));
    printf("\n");
    
    return 0;
}

程序输出结果:

习题22

试利用循环队列(长度为k)存储,编写求斐波那契数列的前n(n>k)项()的算法,其函数定义如下:

#include <stdio.h>
#include "CirQueue.h"

int f(int n)
{
    if (n < 0)
        printf("ERROR!");
    
    if (n == 0)
        return 0;
    else if (n == 1)
        return 1;
    else
        return f(n - 2) + f(n - 1);
}

int main(void)
{
    CirQueue Q;
    int i;
    
    InitQueue(&Q);
    int k = 10, n;
    printf("开始创建斐波那契数列, k = %d\n", k);
    for (n = 0; n <= k; n++)
        EnQueue(&Q, f(n));
    printf("斐波那契数列列表:\n");
    i = 0;
    while (!IsQueueEmpty(&Q))
        printf("f%d=%d ", i++, ExQueue(&Q));
    printf("\n");
    return 0;
}

程序输出结果:

对比数学软件Mathematica的运算结果:

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值