数据结构-栈和队列

目录

一、栈基础知识

1.栈的特点

2.栈的定义

3.栈的术语

二、栈的实现及基本操作

1.栈的定义实现

2.栈的初始化

3.入栈操作(记得判断是否栈满)

4.出栈操作(记得判断是否栈空)

5.链栈的c语言类型定义

三、栈的应用举例

 1.进制转换问题

2.括号匹配问题

四、队列的基础知识

 1.定义:

2.术语:

五、队列基本操作

1.链队列

(1)结点实现

(2)带头结点的链队列初始化

(3)带头结点的链队列的入队操作

(4)带尾结点的链队列的出队操作

2.循环队列


一、栈基础知识

1.栈的特点

后进先出(LIFO)

2.栈的定义

是一种特殊的线性表,其插入和删除操作均
在表的一端进行,是一种运算受限的线性表。

3.栈的术语

栈顶(top)是栈中允许插入和删除的一端
栈底(bottom)是栈顶的另一端

二、栈的实现及基本操作

1.栈的定义实现

typedef struct{
    SElemType *base;
    SElemType *top;
    int stacksize;
}SqStack;
Sqstack S;

2.栈的初始化

int InitStack(SqStack *s){
    s->base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
    if(!s->base) exit(OVERFLOW);
    s->top=s->base;
    s->stacksize=STACK_INIT_SIZE;
    return OK;
}

3.入栈操作(记得判断是否栈满)

重点:*S.top=e; S.top++;即*S.top++=e;

int Push(SqStack *S,SElemType e){
    if(S->top-S->base>=S->stacksize){
        S->base=(SElemType*)realloc(S->base,(S->stacksize+STACKINCREMENT)*sizeof(SElemType));
    if(!S->base) exit(OVERFLOW);
    S->top=S->base+S->stacksize;
    S->stacksize+=STACKINCREMENT;
    }
    *S->top++=e;
    return OK;
}

4.出栈操作(记得判断是否栈空)

int Pop(SqStack *S,SElemType *e){
    if(S->top==S->base) return error;
    else{
        *e=*(S->top-1);//注意:不是e=S->top-1!!!后者只是在函数内部改变了e的指向
        S->top--;
        return OK;
    }
}

5.链栈的c语言类型定义

链栈的入栈->单链表的头插法

链栈的出栈->单链表删除头结点的后驱结点

三、栈的应用举例

 1.进制转换问题

取余依次求出个位、十位、百位......但写数习惯是高位到低位,刚好符合栈的特点

void conversion()
{
    SqStack *S;
    S=(SqStack*)malloc(sizeof(SqStack));
    InitStack(S);
    int N;
    scanf("%d",&N);
    while(N)
    {
        Push(S,N%8);
        printf("%d\n",N%8);
        N=N/8;
    }
    while(!StackEmpty(*S)){
        int *p = (int*)malloc(sizeof(int));//!!!一定要分配空间,不要初始化成null,因为进函数后            
                                           //直接解引用会把程序跑死
        Pop(S,p);
        printf("%d",*p);
    }

}

2.括号匹配问题

int check()
{
    SqStack *P;
    P=(SqStack*)malloc(sizeof(SqStack));
    InitStack(P);
    SElemType ch;
    SElemType *e=(SElemType*)malloc(sizeof(SElemType));
    while((ch=getchar())!='#')
    {
        switch(ch)
        {
        case '(':
        case'[':
        case'{':
            Push(P,ch);
            break;
        case ')':
            if(StackEmpty(*P)) return FALSE;
            else
            {
                Pop(P,e);
                if(*e!='(') return FALSE;
            }
            break;
        case ']':
            if(StackEmpty(*P)) return FALSE;
            else
            {
                Pop(P,e);
                if(*e!='[') return FALSE;
            }
            break;
        case '}':
            if(StackEmpty(*P)) return FALSE;
            else
            {
                Pop(P,e);
                if(*e!='{') return FALSE;
            }
            break;
        default:
            break;
        }
    }
    if(StackEmpty(*P)) return TRUE;
    else return FALSE;
}

四、队列的基础知识

 1.定义:

队列 (Queue)—— 是一种运算受限的特殊的线性
表,它只允许在表的一端进行插入,而在表的另一端
进行删除。

2.术语:

队尾(rear)是队列中允许插入的一端
队头(front)是队列中允许删除的一端

五、队列基本操作

1.链队列

(1)结点实现

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

typedef struct{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;


(2)带头结点的链队列初始化

Status InitQueue(LinkQueue *Q){
    Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));
    if(!Q->front) exit(OVERFLOW);
    Q->front->next=NULL;
    return OK;
}

(3)带头结点的链队列的入队操作

Status EnQueue(LinkQueue *Q,QElemType e){
    QueuePtr p;
    p=(QueuePtr)malloc(sizeof(QNode));
    if(!p) exit(OVERFLOW);
    p->data=e;
    Q->rear=p;
    Q->rear=Q->rear->next;
    return OK;
}

(4)带尾结点的链队列的出队操作

Status DeQueue(LinkQueue *Q,QElemType *e){
    if(Q->front==Q->rear) return error;
    p=Q->front->next;
    *e=*(p->data);
    Q->front->next=p->next;
    if(Q->rear==p) Q->rear=Q->front;//!!!这一步是为了防止原队列中就只有一个元素,如果直接释放该 
                                    //元素,Q->rear就变成了野指针
    free(p);
    return OK;
}

2.循环队列

(1)循环队列类型实现

typedef struct{
    QElemType *base;
    int front;//即数组下标
    int rear;//即数组下标
}SqQueue;

空状态和满状态都满足Q.front==Q.rear->判别队列是空还是满:

(1)另设一个标志区别队列是空是满,如:计数变量,记录元素个数

(2)牺牲一个存储空间,以队头指针在队列尾指针的下一个位置作为队列呈满状态的标志

Status InitQueue(SqQueue *Q){
    Q->base=(QElemType*)malloc(sizeof(QElemType));
    if(!Q->base) exit(OVERFLOW);
    Q->front=Q->rear=0;//!!!注意和链队列的区别
    return OK;
}

 (2)入队列操作

Status EnQueue(SqQueue *Q,QElemType e){
    if((Q->rear+1)%MAXSIZE==Q->front) return ERROR;
    *(Q->base[Q->rear])=e;//!
    Q->rear=(Q->rear+1)*MAXSIZE;//!
    return OK;
}

(3)出队列操作

Status DeQueue(SqQueue *Q,QElemType *e){
    if(Q->front==Q->rear) return ERROR;
    *e=*(Q->base[Q->front])
    Q->front=(Q->front+1)%MAXSIZE;
    return OK;
}

(4)求队列长度

int QueueLength(SqQueue Q){
    return (Q->rear-Q->front+MAXSIZE)%MAXSIZE;
}

3.双端队列

(1)双端队列定义

双端队列是一种特殊的线性表,特殊在限定插入
和删除操作只能在表的两端进行。

(2)双端队列应用

判断是不是回文数:


 

 *注意表达式求值、括号匹配、数值转换、迷宫求解的应用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值