超详细最全数据结构个人笔记【顺序栈与链式栈】

1.基本概念

​ 栈是一种逻辑结构,是特殊的线性表,特殊在只能在固定一端操作

只要满足上述条件,那么这种特殊的线性表就会呈现出一种"后进先出"的逻辑,这种逻辑就被称为栈,栈在生活中到处可见,比如堆叠的盘子、电梯中的人等等。

在这里插入图片描述

由于约定了只能在线性表固定的一端进行操作,于是给栈这种特殊的线性表的"插入"、“删除”,另起了下面这些特殊的名称:

  1. 栈顶 : 可以进行插入删除的一端

  2. 栈底:栈顶的对端

  3. 入栈: 将节点插入栈顶之上,也称为压栈,函数名通常为push()

  4. 出栈:将节点从栈顶剔除,也称为弹栈,函数名通常额外pop()

  5. 取栈顶: 取得栈顶元素,但不出栈,函数名通常为top()

    基于这种固定一端操作的简单约定,栈获得了"后进先出"的基本特征,如图所示,最后一个放入的元素,最先被拿出来:

在这里插入图片描述

### 2.存储方式

​	栈只是一种数据逻辑,如何将数据存储于内存则是另外一回事,一般而言,可以采用顺序存储形成顺序栈,或者采用链式存储形成链式栈。

​	1.顺序栈

​		顺序存储意味着开辟一块连续的内存用于存储数据节点,一般而言,管理栈数据除了需要一块连续的内存之外,还需要记录栈的总容量、当前栈的元素个数、当前栈顶元素位置,如果有多线程还需要配合互斥锁和信号量等信息,为了方便管理,通常将这些信息统一于一个管理结构体中;

```c
struct seqStack
{
    datatype *data; // 顺序栈入口
    int size;       // 顺序栈总容量
    int top;        // 顺序栈栈顶元素下标
};
```

​	![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/3526b25e2861413480bc948d0c7e7b78.png)


2.链式栈

​	链式栈的组织形式与链表无异,只不过插入删除被约束在固定的一端。为了便于操作,通常也会创建所谓管理结构体,用来存储栈顶指针、栈元素个数等信息:

```c
// 链式栈节点
typedef struct node
{
    datatype data;
    struct node *next;
}node;

// 链式栈管理结构体
struct linkStack
{
    node *top; // 链式栈栈顶指针
    int  size; // 链式栈当前元素个数
};
```

​					![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/43a3c29b892c41e18679bc8c71d40ceb.png)

3.基本操作

​ 不管是顺序栈,链式栈,栈的操作逻辑都是一样的,但由于存储形式不同,代码的实现是不同的。下面分别将顺序栈和链式栈的基本核心操作罗列出来:

1.顺序栈

// 顺序栈管理结构体
typedef struct 
{
    datatype *data; // 顺序栈入口
    int size;       // 顺序栈总容量
    int top;        // 顺序栈栈顶元素下标
}seqStack;


// 初始化空栈
seqStack *initStack(int size)
{
    seqStack *s = (seqStack *)malloc(sizeof(seqStack))
    if(s != NULL)
    {
        s->data = (datatype *)malloc(sizeof(datatype) * size));
        if(s->data == NULL)
        {
            free(s);
            return NULL;
        }
        s->size = size;
        s->top  = -1;
    }

    return s;
}

// 判断栈是否已满
bool isFull(seqStack *s)
{
    return s->top == s->size-1;
}

// 判断栈是否为空
bool isEmpty(seqStack *s)
{
    return s->top == -1;
}

// 入栈
bool push(seqStack *s, datatype data)
{
    if(isFull(s))
        return false;

    s->data[++s->top] = data;
    return true;
}

// 出栈
bool pop(seqStack *s, datatype *pm)
{
    if(top(s, pm) == false)
        return false;

    s->top--;
    return true;
}

// 取栈顶元素
bool top(seqStack *s, datatype *pm)
{
    if(isEmpty(s))
        return false;

    *pm = s->data[s->top];
    return true;
}

「题目1」

使用顺序栈,接收键盘的输入,实现如下功能:

  1. 输入数字时,依次入栈。

  2. 输入字母时,依次出栈。

  3. 每次入栈或者出栈,都将顺序栈中的各个元素输出出来。

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    typedef int dataType;
    
    // 声明栈管理结构体
    typedef struct seqStack
    {
        dataType *data; // 指向数组首元素地址
        int size; // 数组空间
        int top; // 栈顶,数组下标
    }seqStack;
    
    // 初始化顺序栈
    struct seqStack *init_seqStack(int cap)
    {
        seqStack *st = malloc(sizeof(seqStack));
        if(st == NULL)
            return NULL;
        st->data = calloc(cap,sizeof(dataType));
        if(st->data == NULL)
            return NULL;
    
        st->size = cap;
        st->top = -1;// 栈顶,其实就是数组的下标
    
        return st;
    }
    
    // 判断栈是否满
    bool isFull(seqStack *st)
    {
        if(st->top == st->size-1)
            return true;
        return false;
    }
    
    // 入栈
    bool push(seqStack *st, dataType data)
    {
        if(isFull(st))
            return false;
    
        st->data[++st->top] = data;
    
        return true;
    }
    
    // 判断栈是否空
    bool isEmpty(seqStack *st)
    {
        return st->top == -1;
    }
    
    // 去栈顶元素不出栈
    bool top(seqStack *st, dataType *data)
    {
        if(isEmpty(st))
            return false;
    
        // 取栈顶元素
        *data = st->data[st->top];
    
        return true;
    }
    
    // 出栈
    bool pop(seqStack *st, dataType *data)
    {
        // 访问栈顶元素并取出,如果无法访问表示栈顶没有元素可取
        if(!top(st,data))
            return false;
        st->top--;
        return true;
    }
    
    // 显示
    void show(seqStack *st)
    {
        if(isEmpty(st))
        {
            printf("空栈\n");
            return;
        }
        
        for(int i = st->top; i >= 0; i--)
        {
            printf("  %d",st->data[i]);
            if(i == st->top)
            {
                printf("<---栈顶");
                printf("\n");
            }
        }
        printf("-----------------\n");
        printf("一共有%d个元素\n",st->top+1);
    }
    
    int main(int argc, char const *argv[])
    {
        // 初始化栈
        seqStack *st = init_seqStack(5);
        if(st == NULL)
        {
            printf("init stack failed:\n");
            return -1;
        }
    
        while(1)
        {
            dataType data;
            if(1 == scanf("%d",&data)) // 输入整数
            {
                if(false == push(st,data))
                {
                    printf("栈满,无法入栈\n");
                    continue;
                }
                
            }
            else // 输入字母
            {
                //printf("%d\n",__LINE__);
                // 清空输入缓冲区
                while(getchar() != '\n');
                // 出栈
                if(!pop(st,&data))
                {
                    printf("栈空,无法出栈\n");
                    break;
                }
            }
            show(st);
        }
    
        return 0;
    }
    
    

2.链式栈

// 链式栈节点
typedef struct node
{
    datatype data;
    struct node *next;
}node;

// 链式栈管理结构体
typedef struct linkStack
{
    node *top; // 链式栈栈顶指针
    int  size; // 链式栈当前元素个数
}linkStack;

// 初始化空栈
linkStack * initStack(void)
{
	linkStack * s = (linkStack *)malloc(sizeof(linkStack));
    if(s != NULL)
    {
        s->top  = NULL;
        s->size = 0;
    }
	return s;
}

// 判断栈是否为空
bool isEmpty(linkStack *s)
{
	return (top->size == 0);
}

// 入栈
bool push(linkStack *s, datatype data)
{
    // 创建链表节点
    node *new = (node *)malloc(sizeof(node));
	if(new == NULL)
		return false;

	new->data = data;

    // 将节点置入栈顶
	new->next = s->top;
	s->top = new;

    // 更新栈元素个数
    s->size++;
	return true;
}

// 出栈
bool pop(linkStack *s, datatype *pm)
{
	if(isEmpty(s))
		return false;

	linkStack *tmp = s->top;

    // 将原栈顶元素剔除出栈
	s->top    = tmp->next;
    tmp->next = NULL;

    // 返回栈顶元素,并释放节点
    *pm = tmp->data;
	free(tmp);

	return true;
}

// 取栈顶元素
bool top(linkStack *s, datatype *pm)
{
	if(isEmpty(s))
		return false;

    // 返回栈顶元素,并释放节点
    *pm = s->top->data;
	return true;
}

「题目」

  1. 使用链式栈,实现十进制转八进制:键盘输入一个十进制数,经过链式栈的相关算法,输出八进制数。

    在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值