第3章_堆栈和队列

来源:互联网 发布:音乐合成软件 编辑:程序博客网 时间:2024/06/15 23:15

堆栈和队列都是特殊的线性表。线性表、堆栈和队列三者的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的插入和删除操作不受限制,而堆栈只能在栈顶插入和删除,队列只能在队尾插入在队头删除。堆栈和队列都可以分别用顺序存储结构和链式存储结构。顺序队列通常采用顺序循环队列方法实现,因为顺序循环队列可以避免顺序队列的“假溢出”问题。
堆栈和队列在各种类型的软件中应用十分广泛,堆栈可以用来完成数据序列的特定转换,队列可以用作 数据元素序列的缓冲存储。

顺序堆栈

SeqStack.h

//顺序堆栈结构体定义typedef struct {    DataType stack[MaxStackSize];    int top;}SeqStack;//1.初始化void StackInitiate(SeqStack*S){    S->top = 0;}//2.判断是否为空int StackNotEmpty(SeqStack S){    //判断顺序堆栈S非空否,非空返回1,否则返回0    if(S.top <= 0) return 0;    else return 1;}//3.入栈int StackPush(SeqStack*S,DataType x){    //把数据元素值x压入顺序堆栈S,入栈成功返回1,否则返回0    if(S->top >= MaxStackSize)    {        printf("堆栈已满无法插入!\n");        return 0;    }    else    {        S->stack[S->top] = x;        S->top++;        return 1;    }}//4.出栈int StackPop(SeqStack*S,DataType*d){    //弹出顺序堆栈S的栈顶数据元素值到参数d,出栈成功返回1,否则返回0    if(S->top <= 0)    {        printf("堆栈已空无数据元素出栈!\n");        return 0;    }    else    {        S->top--;        *d = S->stack[S->top];        return 1;    }}//5.取栈顶数据元素int StackTop(SeqStack S,DataType*d){    if(S.top <= 0)    {        printf("堆栈已空!\n");        return 0;    }    else    {        *d = S.stack[S.top - 1];        return 1;    }}

main.c

#include<stdio.h>               //该文件包含printf()函数#include<stdlib.h>              //该文件包含exit()函数#define MaxStackSize 100        //定义MaxStackSize 为100typedef int DataType;           //定义DataType为int数据类型#include "SeqStack.h"void main(void){    SeqStack myStack;    int i,x;    StackInitiate(&myStack);    for(i = 0;i < 10; i++)    {        if(StackPush(&myStack,i + 1) == 0)  //入栈10个数据元素        {            printf("错误!\n");            return ;        }    }    if(StackTop(myStack,&x) == 0)       //取栈顶数据元素    {        printf("错误!\n");        return ;    }    else    {        printf("当前栈顶数据元素为:%d\n",x);    }    printf("依次出栈的数据元素序列如下:\n");    while(StackNotEmpty(myStack))    {        StackPop(&myStack,&x);        printf("%d ",x);    }    printf("\n");}/*当前栈顶数据元素为:10依次出栈的数据元素序列如下:10 9 8 7 6 5 4 3 2 1Press any key to continue*/

这里写图片描述

链式堆栈

typedef struct snode{    DataType data;    struct snode *next;}LSNode;//1.初始化void StackInitiate(LSNode** head){    if((*head = (LSNode*)malloc(sizeof(LSNode))) == NULL) exit(1);    (*head)->next = NULL;}//2.判空int StackNotEmpty(LSNode*head){    //判断堆栈是否非空,非空返回1;空返回0    if(head->next == NULL) return 0;    else return 1;}//3.入栈int StackPush(LSNode*head,DataType x){    //把数据元素x插入链式堆栈head的栈顶作为新的栈顶    LSNode*p;    if((p = (LSNode*)malloc(sizeof(LSNode))) == NULL)    {        printf("内存空间不中无法插入!\n");        return 0;    }    p->data = x;                p->next = head->next;   //新结点链入栈顶    head->next = p;         //新结点成为新的栈顶    return 1;}//4.出栈int StackPop(LSNode*head,DataType* d){    LSNode*p = head->next;    if(p == NULL)    {        printf("堆栈已空出错!\n");        return 0;    }    head->next = p->next;   //删除原栈顶结点    *d = p->data;           //原栈顶结点元素赋予d    free(p);                //释放原栈顶结点内存空间    return 1;}//5.取栈顶数据元素int StackTop(LSNode*head,DataType*d){    //取栈顶元素并把栈顶元素由参数d带回    LSNode *p = head->next;    if(p == NULL)    {        printf("堆栈已空出错!");        return 0;    }    *d = p->data;    return 1;}//6.撤消动态申请空间void Destroy(LSNode*head){    LSNode*p,p1;    p = head;    while(p != NULL)    {        p1 = p;        p = p->next;        free(p1);    }}
#include<string.h>#include<stdio.h>               //该文件包含printf()函数#include<stdlib.h>              //该文件包含exit()函数#define MaxStackSize 100typedef char DataType;#include "SeqStack.h"void ExpIsCorrect(char exp[],int n);void main(void){    char a[] = "(())abc{]()}";  //左右括号配对次序不正确    char b[] = "(()))abc{[]}";  //右括号多于左括号    char c[] = "(()()abc{[]}";  //左括号多于右括号    char d[] = "(())abc{[]}";   //左右括号配匹正确    int n1 = strlen(a);    int n2 = strlen(b);    int n3 = strlen(c);    int n4 = strlen(d);    ExpIsCorrect(a,n1);    ExpIsCorrect(b,n2);    ExpIsCorrect(c,n3);    ExpIsCorrect(d,n4);}/************************************************************************//* 1.假设一个算术表达式的包含圆 括号、方括号和花括号三种类型的括号,编写一个判别表达式中括号是否正确配对的函数,并设遍地开花个测试主函数。算法思想:算术表达式中右括号和左括号匹配的次序正好符 合后到的括号要最先被匹配的“后进先出”堆栈操作特点,因此,可以借助一个堆栈来进行判断。括号匹配共有4种情况:a.左右括号配对次序不正确;b.右括号多于左括号c.左括号多于右括号d.左右括号匹配正确*//************************************************************************/void ExpIsCorrect(char exp[],int n){    //判断有n个字符的字符串exp左右括号是否配对正确    SeqStack myStack;       //定义链式堆栈    int i;    char c;    StackInitiate(&myStack);    for(i = 0;i < n; i++)    {        if((exp[i] == '(')  || (exp[i] == '[') || (exp[i] == '{'))         {            StackPush(&myStack,exp[i]);        }        else if(exp[i] == ')' && StackNotEmpty(myStack)             && StackTop(myStack,&c) && c == '(')        {            StackPop(&myStack,&c);      //出栈        }        else if(exp[i] == ')' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '(')        {            printf("左右括号配对次序不正确!\n");            return ;        }        else if(exp[i] == ']' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c == '[')        {            StackPop(&myStack,&c);        }        else if(exp[i] == ']' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '[')        {            printf("左右括号配对次序不正确!\n");            return ;        }        else if(exp[i] == '}' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c == '{')        {            StackPop(&myStack,&c);  //出栈        }        else if(exp[i] == '}' && StackNotEmpty(myStack) && StackTop(myStack,&c) && c != '{')        {            printf("左右括号配对次序不正确!\n");            return ;        }        else if(((exp[i] == ')') || (exp[i] == ']') || exp[i] == '}') && !StackNotEmpty(myStack))        {            printf("右括号多于左括号!\n");            return ;        }    }    if(StackNotEmpty(myStack))    {        printf("左括号多于右括号!\n");    }    else    {        printf("左右括号匹配正确!\n");    }}/*左右括号配对次序不正确!右括号多于左括号!左括号多于右括号!左右括号匹配正确!Press any key to continue*/

这里写图片描述

队列也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系与线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作,在其另一端进行删除操作。队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队头和队尾分别由队头指示器(或称队头指针)和队尾指示器(或称队尾指针)指示。队列的插入操作通常称为入队列,队列的删除操作通常称为出队列。当队列中没有数据元素时称为空队列。

顺序队列

typedef struct {    DataType queue[MaxQueueSize];    int rear;       //队尾指针    int front;      //队头指针    int count;      //计数器} SeqCQueue;//1.初始化void QueueInitiate(SeqCQueue*Q) //初始化顺序循环队列Q{    Q->rear = 0;        //定义初始队尾指针下标值    Q->front = 0;       //定义初始队头指针下标值    Q->count = 0;       //定义初始计数器值}//2.非空否int QueueNotEmpty(SeqCQueue Q){    //判断顺序循环队列Q非空否,非空时返回1,否则返回0    if(Q.count != 0) return 1;    else return 0;}//3.入队列int QueueAppend(SeqCQueue*Q,DataType x){    //把数据元素值x插入顺序循环队列Q的队尾,成功返回1,失败则返回0    if(Q->count > 0 && Q->rear == Q->front)    {        printf("队列已满无法插入!\n");        return 0;    }    else    {        Q->queue[Q->rear] = x;        Q->rear = (Q->rear + 1) % MaxQueueSize;        Q->count++;        return 1;    }}//4.出队列int QueueDelete(SeqCQueue*Q,DataType *d){    //删除顺序循环队列Q的队头元素并赋给d,成功返回1,失败返回0    if(Q->count == 0)    {        printf("队列已空无数据元素出队列!\n");        return 0;    }    else    {        *d = Q->queue[Q->front];        Q->front = (Q->front + 1) % MaxQueueSize;        Q->count--;        return 1;    }}//5.取队头元素int QueueGet(SeqCQueue Q,DataType*d){    //取顺序循环队列Q的当前队头元素并赋给d,成功返回1,失败返回0    if(Q.count == 0)    {        printf("队列已空无数据元素可取!\n");        return 0;    }    else    {        *d = Q.queue[Q.front];        return 1;    }}

链式队列

typedef struct qnode {    DataType data;    struct qnode * next;}LQNode;typedef struct  {    LQNode* front;  //队头指针    LQNode* rear;   //队尾指针}LQueue;//1.初始化void QueueInitiate(LQueue*Q){    Q->rear = NULL;     //定义初始队尾指针    Q->front = NULL;    //定义初始队头指针}//2.非空否int QueueNotEmpty(LQueue Q){    //判断链式队列Q非空否,非空返回1,否则返回0    if(Q.front == NULL) return 0;    else return 1;}//3.入队列int QueueAppend(LQueue*Q,DataType x){    //把数据元素值x插入链式队列Q的队尾,入队列成功返回1,否则返回0    LQNode*p;    if((p = (LQNode*)malloc(sizeof(LQNode))) == NULL)    {        printf("内存空间不中!");        return 0;    }    p->data = x;    p->next = NULL;    if(Q->rear != NULL) Q->rear->next = p;    Q->rear = p;    if(Q->front == NULL) Q->front = p;    return 1;}//4.出队列int QueueDelete(LQueue*Q,DataType*d){    //删除链式队列Q的队头数据元素值到d,出队列成功返回1,否则返回0    LQNode*p;    if(Q->front == NULL)    {        printf("队列已空无数据元素出队列!\n");        return 0;    }    else    {        *d = Q->front->data;        p = Q->front;        Q->front = Q->front->next;        if(Q->front == NULL) Q->rear = NULL;        free(p);        return 1;    }}//5.取队头数据元素int QueueGet(LQueue Q,DataType*d){    //取链式队列Q的当前队头数据元素值到d,成功返回1,否则返回0    if(Q.front == NULL)    {        printf("队列已空无数据元素出队列!\n");        return 0;    }    *d = Q.front->data;    return 1;}//6.撤消动态申请空间void Destroy(LQueue Q){    LQNode*p,*p1;    p = Q.front;    while(p != NULL)    {        p1 = p;        p = p->next;        free(p1);    }}

队列应用

#include <stdio.h>#include <string.h>#define MaxQueueSize 100#define MaxStackSize 100typedef char DataType;#include "SeqQueue.h"#include "SeqStack.h"void HuiWen(char str[]);void main(void){    char str1[] = "ABCDEDCBA";    char str2[] = "ABCDEDCAB";    HuiWen(str1);    HuiWen(str2);}/*ABCDEDCBA是回文!ABCDEDCAB不是回文!Press any key to continue*//************************************************************************//* 1.编程序判 断一个字符序列是否是回文。回文是指一个字符序列以中间字符为基准两边字符完全相同,如字符序列“ABCDEDCBA”就是回文,而字符序列“ABCDEDBAC”就不是回文。算法思想:设字符数组str中存放了要判断的字符串。把字符数组中的字符逐个分别存入队列和堆栈,然后逐个出队列和退栈并比较出队列的字符和退栈的字符是否相等,若全部相等则该字符序列是回文,否则就不是回文。*//************************************************************************/void HuiWen(char str[]){    SeqCQueue myQueue;    SeqStack myStack;    char x,y;    int i,length;    length = strlen(str);    QueueInitiate(&myQueue);    StackInitiate(&myStack);    for(i = 0;i < length; i++)    {        QueueAppend(&myQueue,str[i]);        StackPush(&myStack,str[i]);    }    while(QueueNotEmpty(myQueue) == 1 && StackNotEmpty(myStack) == 1)    {        if(QueueDelete(&myQueue,&x) == 1 && StackPop(&myStack,&y) == 1 && x != y)        {            printf("%s不是回文!\n",str);            return ;        }    }    if(QueueNotEmpty(myQueue) || StackNotEmpty(myStack))    {        printf("%s不是回文!\n",str);    }    else        printf("%s是回文!\n",str);}

这里写图片描述

优先级队列

优先级队列是带有优先级的队列。队列是数据元素的先进先出表,即最先进入队列的元素将最先被删除。但在有些软件系统中,有时也要求把进入队列中的元素分优先级,出队列时首先选择优先级最高的元素出队列(即优先级高的元素被先服务),对优先级相同的元素则按先进先出的原则出队列。显示,优先级队列和一般队列的主要区别是:优先级队列的出队列操作不是把队头元素出队列,而是把队列中优先级最高的数据元素出队列。

顺序优先级队列

typedef struct  {    int priority;    ElemType elem;} DataType;typedef struct  {    DataType queue[MaxQueueSize];    int size;}SeqPQueue;//1.初始化void QueueInitiate(SeqPQueue*Q){    Q->size = 0;    //定义初始元素个数}//2.空否int QueueNotEmpty(SeqPQueue Q){    //判断顺序优先队列Q非空否,非空返回1,否则返回0    if(Q.size <= 0) return 0;    else return 1;}//3.入队int QueueAppend(SeqPQueue*Q,DataType x){    //把数据元素值x插入顺序优先队列Q的队尾,成功返回1,失败返回0    if(Q->size >= MaxQueueSize)    {        printf("队列已满无法插入!\n");        return 0;    }    else    {        Q->queue[Q->size] = x;        Q->size++;        return 1;    }}//4.出队int QueueDelete(SeqPQueue*Q,DataType*d){    //删除顺序优先队列Q中优先级最高的元素并赋给d,成功返回1,失败返回0    DataType min;    int minIndex,i;    if(Q->size <= 0)    {        printf("队列已空无数据元素出队列!\n");        return 0;    }    else    {        min = Q->queue[0];  //初始选queue[0]为优先级最高的元素        minIndex = 0;       //minIndex为优先级最高元素的下标        for(i = 1;i < Q->size; i++)        {            if(Q->queue[i].priority < min.priority)            {                min = Q->queue[i];                minIndex = i;            }        }        *d = Q->queue[minIndex];    //找到优先级最高的元素        for(i = minIndex + 1; i < Q->size; i++) //数据元素依次前移            Q->queue[i - 1] = Q->queue[i];        Q->size--;                  //元素个数减1        return 1;    }}int QueueGet(SeqPQueue*Q,DataType*d){    //取顺序优先队列Q中优先级最高的元素并赋给d,成功返回1,失败返回0    DataType min;    int minIndex,i;    if(Q->size <= 0)    {        printf("队列已空无数据元素可取!\n");        return 0;    }    else    {        min = Q->queue[0];  //初始选queue[0]为优先级最高的元素        minIndex = 0;       //minIndex为优先级最高元素的下标        for(i = 1;i < Q->size; i++)        {            if(Q->queue[i].priority < min.priority)            {                min = Q->queue[i];                minIndex = i;            }        }        *d = Q->queue[minIndex];        return 1;    }}

优先级队列应用

#include <stdio.h>#include <stdlib.h>#define MaxQueueSize 100typedef int ElemType;       //定义data域的数据类型为int#include "SeqPQueue.h"      //包含顺序优先级队列/************************************************************************//* 1.设计一个程序,模仿操作系统的进程管理问题。进程服务按优先级高的先服务,优先级相同的先到先服务的原则管理。设文件task.dat中存放了仿真进程服务请求数据,其中第一列表示进程的任务号,第二列表示进程的优先级。文件task.dat中的仿真进程服务请求数据如下:1   302   203   404   205   0设计:文件task.dat中每一个进程服务的请求数据包含任务号和优先级两项。可直接用上述结构体DataType中的抽象数据类型ElemType为int数据类型。*//************************************************************************/void main(void){    SeqPQueue myPQueue;    FILE * fp;    DataType task;    int i;    if((fp = fopen("task.dat","r")) == NULL)    {        printf("不能打开文件task.dat!");        exit(0);    }    QueueInitiate(&myPQueue);       //初始化顺序优先级队列    while(!feof(fp))    {        fscanf(fp,"%d\t%d",&task.elem,&task.priority);        QueueAppend(&myPQueue,task);        //把数据入队列    }    i = 1;    printf("序号\t任务号\t优先级\n");    while(QueueNotEmpty(myPQueue))  //逐个出队    {        QueueDelete(&myPQueue,&task);   //出队        printf("%d\t%d\t%d\n",i,task.elem,task.priority);        i++;    }}/*序号    任务号  优先级1       5       02       2       203       4       204       1       305       3       40Press any key to continue*/

这里写图片描述

原创粉丝点击