数据结构4-栈、队列

摘要:本文系统介绍了栈和队列两种基础数据结构。栈采用"先进后出"原则,分为顺序栈和链式栈,详细说明了压栈、出栈等基本操作及其实现方法。队列遵循"先进先出"规则,同样分为顺序队列和链式队列,重点讲解了循环队列的判满条件(牺牲一个存储空间)和操作实现。最后通过编程练习展示了如何用链式栈(需两次压栈)和链式队列(直接实现)来完成输入输出顺序一致的功能,提供了完整的代码实现方案。文章内容涵盖数据结构基本概念、分类及具体实现。

一、栈

1、栈的概念:

        1. 先进后出,后进先出
        2. 栈顶:允许入栈和出栈的一端称为栈顶
        3. 栈底:不允许入栈和出栈的一端称为栈底
        4. 入栈(压栈):将元素放入栈顶位置
        5. 出栈(弹栈):将栈顶元素取出
        6. 栈针:记录栈顶位置的标记

2、栈的分类:

        顺序栈、链式栈

3、顺序栈:

3.1 概念:

        1. 增栈:栈的方向自低向高增长
        2. 减栈:栈的方向自高向低增长
        3. 空栈:栈针指向要入栈的位置
        4. 满栈:栈针指向栈顶元素的位置

3.2 顺序栈的实现
3.2.1 节点的定义

3.2.2 顺序栈的创建
  • 申请存放标签的空间
  • 申请存放数据的空间

3.2.3 顺序栈的销毁:
  • 销毁存放数据的空间
  • 销毁存放标签的空间

3.2.4判断是否为空栈
  • 栈针为0即为空栈

3.2.5是否为满栈
  • 栈针与tlen相同即为满栈

3.2.6压栈(输入数据)
  • 将元素放入栈顶位置

  • 栈针位置++

3.2.7出栈
  • 栈针位置--
  • 将栈顶元素出栈

4、链式栈

4.1概念

  1. 使用链表的思想实现链式栈
  2. 参考单向链表节点定义
  3. 压栈参考单向链表头插法
  4. 出栈返回链表第一个有效节点的值,并删除该节点
  5. 销毁栈参考单向链表销毁

4.2链式栈的实现

#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"

//创建、判断、插入头插法、出栈、销毁
linknode *create_empty_linkstack(void)
{
    linknode *ptmpnode = NULL;
    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return NULL;
    }
    ptmpnode->pnext = NULL;

    return ptmpnode; 
}


int is_empty_linkstack(linknode *phead)
{
    return NULL == phead->pnext;     
}


int push_linkstack(linknode *phead,datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return -1;
    }
    ptmpnode->data = tmpdata;
    ptmpnode->pnext = phead->pnext;
    phead->pnext = ptmpnode;

    return 0;
}


datatype pop_linkstack(linknode *phead)
{
    linknode *ptmpnode = NULL;
    datatype deledata;

    ptmpnode = phead->pnext;
    deledata = ptmpnode->data;
    phead->pnext = ptmpnode->pnext;
    free(ptmpnode);
    return deledata;   
       
}


int destroy_linkstack(linknode **pphead)
{
    linknode *ptmpnode = NULL;
    linknode *pfreenode = NULL;

    ptmpnode = *pphead;
    pfreenode = *pphead;
    while (ptmpnode != NULL)
    {
        ptmpnode = ptmpnode->pnext;
        free(pfreenode);
        pfreenode = ptmpnode;
    }
    *pphead = NULL;

    return 0;

}

二、队列

1、概念:

        1. 先进先出,后进后出
        2. 队头:出队的一端
        3. 队尾:入队的一端
        4. 入队:将元素放入队列末尾
        5. 出队:将元素从队头中取出

2、分类:

        顺序队列(循环队列)、链式队列

3、顺序队列

3.1基本类型

3.2顺序队列的实现
3.2.1顺序队列的创建

3.2.2顺序队列销毁

3.2.3判断顺序队列是否为空

3.2.4 判断顺序队列是否为满
  • 为避免循环队列空与满的条件冲突,牺牲一个存放数据的空间,将tail+1 == head作为判断队满的条件
  • 循环队列如果head或者tail下标超过tlen范围,需要对tlen取余,保障head和tail的值在队列下标范围内变

3.2.5顺序队列入队

3.2.6顺序队列出队

4、链式队列

4.1概念

  1. 使用链表的思想实现链式栈
  2. 参考单向链表节点定义
  3. 压栈参考单向链表尾插法
  4. 出栈返回链表第一个有效节点的值,并删除该节点
  5. 销毁栈参考单向链表销毁

4.2链式队列的实现

#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>

//创建、判断、插入只能尾插法、出队、销毁
linknode *create_empty_linkqueue(void)

    //单向链表创建

    linknode *ptmpqueue = NULL;
    ptmpqueue = malloc( sizeof(linknode));
    if (NULL == ptmpqueue)
    {
        perror("fail to malloc");
        return NULL;
    }
    ptmpqueue->pnext = NULL;
    return ptmpqueue;
   
}

int is_empty_linkqueue(linknode *phead)
{
     //链式队判断是否为NULL

    return NULL == phead->pnext; 

}

int enter_linkqueue(linknode *phead, datatype tmpdata)
{
     //尾插法
    linknode *ptmpqueue = NULL;
    linknode *plastqueue = NULL;

    ptmpqueue = malloc(sizeof(linknode));
     if (NULL == ptmpqueue)
    {
        perror("fail to malloc");
        return -1;
    }
    ptmpqueue->data = tmpdata;
    ptmpqueue->pnext = NULL;

    plastqueue = phead;
    while (plastqueue->pnext != NULL)
    {
        plastqueue = plastqueue->pnext;
    }
    plastqueue->pnext = ptmpqueue;

    return 0;

}

datatype quit_linkqueue(linknode *phead)
{
    //链式队列的出队
    linknode *ptmpqueue = NULL;
    datatype tmpdata;
    if (is_empty_linkqueue(phead))
    {
        return -1;
    }
    ptmpqueue = phead->pnext;
    phead->pnext = ptmpqueue->pnext;
    tmpdata = ptmpqueue->data;
    free(ptmpqueue);

    return tmpdata;
}

int destroy_linkqueue(linknode **pphead)
{
    //单向队表销毁
    linknode *ptmpqueue = NULL;
    linknode *pfreequeue = NULL;

    ptmpqueue = pfreequeue = *pphead;
    while (ptmpqueue != NULL)
    {
        ptmpqueue = ptmpqueue->pnext;
        free(pfreequeue);
        pfreequeue = ptmpqueue;
    }
    *pphead = NULL;
    return 0;
    
}

三、练习

题目:   实现终端输入若干个数(-1结束),输入和输出顺序相同

eg:输入:1  2  3  4  5  -1

        输出:1  2  3  4  5  -1

1、利用链式栈实现 

(1)题目分析

        链式栈只能使用头插法实现,所以输入:1 2 3 4 5 则输出:5 4 3 2 1 要实现题目操作需得再压栈一次再出栈一次便可以实现

(2)注意事项

        1)实现终端接收数,在循环中利用scanf接受数据,用if条件语句结束循环

        2)  利用两个链式栈实现压栈—出栈—压栈—出栈

                两个方法实现,写一个函数实现,在main函数中调用

(3)代码实现

        linkstack.h

#ifndef __LINKSTACK_H__
#define __LINKSTACK_H__

typedef int datatype;
typedef struct node
{
    datatype data;
    struct node *pnext;
}linknode;

extern linknode *create_empty_linkstack(void);
extern int is_empty_linkstack(linknode *phead);
extern int push_linkstack(linknode *phead,datatype tmpdata);
extern datatype pop_linkstack(linknode *phead);
extern int chance_linkstack(linknode *phead,linknode *phead2);

#endif

        linkstack.c

#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"

linknode *create_empty_linkstack(void)
{
    linknode *ptmpnode = NULL;
    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return NULL;
    }
    ptmpnode->pnext = NULL;

    return ptmpnode;
}

int is_empty_linkstack(linknode *phead)
{
    return NULL == phead->pnext;
}

int push_linkstack(linknode *phead,datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return -1;
    }
    ptmpnode->data = tmpdata;
    ptmpnode->pnext = phead->pnext;
    phead->pnext = ptmpnode;

    return 0;
}

datatype pop_linkstack(linknode *phead)
{
    linknode *ptmpnode = NULL;
    datatype tmpdata;

    if (is_empty_linkstack(phead))
    {
        return -1;
    }
    ptmpnode = phead->pnext;
    tmpdata = ptmpnode->data;
    phead->pnext = ptmpnode->pnext;
    free(ptmpnode);
    return tmpdata;

}

int chance_linkstack(linknode *phead,linknode *phead2)
{
    linknode *ptmpnode = NULL;
    linknode *ptmpnode1 = NULL;

    datatype tmpdata;

    if (is_empty_linkstack(phead))
    {
        return -1;
    }

    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return -1;
    }
    ptmpnode->pnext = phead2->pnext;
    phead2->pnext = ptmpnode; 

    tmpdata = phead->pnext->data;
    ptmpnode->data = tmpdata;

    return 0;
}

        main.c

#include <stdio.h>
#include <stdlib.h>
#include "linkstack.h"

int main(void)
{
    linknode *plinkstack = NULL;
    linknode *plinkstack2 = NULL;
        
    plinkstack = create_empty_linkstack();
    plinkstack2 = create_empty_linkstack();

    while (1)
    {
        scanf("%d",&plinkstack->data);
        if (-1 == plinkstack->data)
        {
            break;
        }
        push_linkstack(plinkstack,plinkstack->data);
    }


#if 0
    //查看是否入栈成功
    while (!is_empty_linkstack(plinkstack))
    {
        printf("%d ",pop_linkstack(plinkstack));
    }
    printf("\n");
#endif

#if 0
    //难为版:自己创个函数
    while (1)
    {

        if (is_empty_linkstack(plinkstack))
        {
            break;
        }

        chance_linkstack(plinkstack,plinkstack2);
        pop_linkstack(plinkstack);

    }

    while (!is_empty_linkstack(plinkstack2))
    {
        printf("%d ",pop_linkstack(plinkstack2));
    }
    printf("\n");
#endif


    //灵活版:简单快捷

    while (!is_empty_linkstack(plinkstack))
    {

        push_linkstack(plinkstack2,pop_linkstack(plinkstack));
        printf("%d ",pop_linkstack(plinkstack2));
    }
    printf("\n");


    return 0;
}

#if 0

        中间内容可以注释掉

#endif

2、链式队列实现

(1)题目分析:

        队列采用的就是尾插法,只需要在链式队列中加入接收数据。

(2)注意事项:

        注意事项尾插法中的找最后一个节点的条件是while(ptmpqueue->pnext != NULL)

(3)代码实现:

        linkqueue.h

#ifndef __LINKQUEUE_H__
#define __LINKQUEUE_H__

typedef int datatype;
typedef struct node 
{
    datatype data;
    struct node *pnext;
}linknode;

extern linknode *create_empty_linkqueue(void);
extern int is_empty_linkqueue(linknode *phead);
extern int enter_linkqueue(linknode *phead, datatype tmpdata);
extern datatype quit_linkqueue(linknode *phead);

#endif

        linkqueue.c

#include "linkqueue.h"
#include <stdio.h>
#include <stdlib.h>

linknode *create_empty_linkqueue(void)
{
    linknode *ptmpqueue = NULL;
    ptmpqueue = malloc( sizeof(linknode));
    if (NULL == ptmpqueue)
    {
        perror("fail to malloc");
        return NULL;
    }
    ptmpqueue->pnext = NULL;
    return ptmpqueue;
}


int is_empty_linkqueue(linknode *phead)
{
    return NULL == phead->pnext;
}

int enter_linkqueue(linknode *phead, datatype tmpdata)
{
    linknode *ptmpqueue = NULL;
    linknode *plastqueue = NULL;

    ptmpqueue = malloc(sizeof(linknode));
    if (NULL == ptmpqueue)
    {
        perror("fail to malloc");
        return -1;
    }

    ptmpqueue->data = tmpdata;
    ptmpqueue->pnext = NULL;

    plastqueue = phead;
    while (plastqueue->pnext != NULL)
    {
        plastqueue = plastqueue->pnext;
    }
    plastqueue->pnext = ptmpqueue;

    return 0;
}

datatype quit_linkqueue(linknode *phead)
{
    linknode *ptmpqueue = NULL;
    linknode *pfreequeue = NULL;
    datatype tmpdata;

    if (is_empty_linkqueue(phead))
    {
        return -1;
    }
    ptmpqueue = phead->pnext;
    phead->pnext = ptmpqueue->pnext;
    tmpdata = ptmpqueue->data;
    free(ptmpqueue);
    return tmpdata;

}

        main.c

#include <stdio.h>
#include <stdlib.h>
#include "linkqueue.h"

int main(void)
{
    linknode *plinkqueue = NULL;

    plinkqueue = create_empty_linkqueue();

    while (1)
    {
        scanf("%d",&plinkqueue->data);

        if (-1 == plinkqueue->data)
        {
            break;
        }
        enter_linkqueue(plinkqueue,plinkqueue->data);
    }

    while (!is_empty_linkqueue(plinkqueue))
    {
        printf("%d",quit_linkqueue(plinkqueue));
    }
    printf("\n");

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值