画解数据结构1-4栈

一.概念

1、栈的定义

   是仅限在 表尾 进行 插入删除线性表

2、栈顶

   是一个线性表,我们把允许 插入删除 的一端称为 栈顶

二。栈的顺序表实现

1、数据结构定义

对于顺序表,在 C语言 中表现为 数组,在进行 栈的定义 之前,我们需要考虑以下几个点:
  1)栈数据的存储方式,以及栈数据的数据类型;
  2)栈的大小;
  3)栈顶指针;

  • 我们可以定义一个  的 结构体,C语言实现如下所示:
#define DataType int        // (1)
#define maxn 100005         // (2)

struct Stack {              // (3)
    DataType data[maxn];    // (4)
    int top;                // (5)
};
  • (1)(1) 用DataType这个宏定义来统一代表栈中数据的类型,这里将它定义为整型,根据需要可以定义成其它类型,例如浮点型、字符型、结构体 等等;
  • (2)(2) maxn代表我们定义的栈的最大元素个数;
  • (3)(3) Stack就是我们接下来会用到的 栈结构体
  • (4)(4) DataType data[maxn]作为栈元素的存储方式,数据类型为DataType,可以自行定制;
  • (5)(5) top即栈顶指针,data[top-1]表示栈顶元素,top == 0代表空栈;

2.入栈

void stackpush(struct stack*stk, datatype dt)//因为会改变stk,所以传入指针
{
stk->data[stk->top]=dt;
stk-<top++;
}

3、出栈

1、动画演示

  如图所示,蓝色元素 为原本在栈中的元素,红色元素 为当前需要 出栈 的元素,执行完毕以后,栈顶的指针减一。具体来看下代码实现。

2、源码详解

  • 出栈 操作,只需要简单改变将 栈顶 减一 即可,代码实现如下:
void StackPopStack(struct Stack* stk) {
    --stk->top;
}

4、清空栈

1、动画演示

  如图所示,对于数组来说,清空栈的操作只需要将 栈顶指针 置为栈底,也就是数组下标 0 即可,下次继续 入栈 的时候会将之前的内存重复利用。

2、源码详解

  • 清空栈的操作只需要将 栈顶 指针直接指向 栈底 即可,对于顺序表,也就是 C语言 中的数组来说,栈底 就是下标 0 的位置了,代码实现如下:
void StackClear(struct Stack* stk) {
    stk->top = 0;
}

5、只读接口

  • 只读接口包含:获取栈顶元素、获取栈大小、栈的判空,实现如下:
DataType StackGetTop(struct Stack* stk) {
    return stk->data[ stk->top - 1 ];      // (1)
}
int StackGetSize(struct Stack* stk) {
    return stk->top;                       // (2)
}
bool StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);             // (3)
}
  • (1)(1) 数组中栈元素从 0 开始计数,所以实际获取元素时,下标为 栈顶元素下标 减一;
  • (2)(2) 因为只有在入栈的时候,栈顶指针才会加一,所以它 正好代表了 栈元素个数;
  • (3)(3) 当 栈元素 个数为 零 时,栈为空。

三。栈的链表实现//区别就是栈本身是数组还是链表

1.数据结构定义

struct stacknode{
Datatype data;
struct stacknode*next;
}
struct stack{
struct stacknode*top;
int size;
}
  • (1) 栈结点元素的 数据域,这里定义为整型;
  • (2)(2) struct StackNode;是对链表结点的声明;
  • (3)(3) 定义链表结点,其中DataType data代表 数据域struct StackNode *next代表 指针域
  • (4)(4) top作为 栈顶指针,当栈为空的时候,top == NULL;否则,永远指向栈顶;
  • (5)(5) 由于 求链表长度 的算法时间复杂度是 O(n)O(n) 的, 所以我们需要记录一个size来代表现在栈中有多少元素。每次 入栈size自增,出栈size自减。这样在询问栈的大小的时候,就可以通过 O(1)O(1) 的时间复杂度。

2.入栈

void push(struct stack*stk,Datatype dt)
{
struct stacknode*insertnode=(struct stacknode*)malloc(sizeof(struct stacknode) );
insertnode->next=stk->top;
stk->top=insertnode;
stk->size++;
}

3.出栈

void delete(struct stack*stk)
{
struct stacknode*cur=stk->top;//由于是已经存在的所以不用malloc
stk->top=cur->next;
free(cur);
stk->size--;
}

4.清空栈

清空栈 可以理解为,不断的出栈,直到栈元素个数为零。

void StackClear(struct Stack* stk) {
    while(!StackIsEmpty(stk)) {       // (1)
        StackPopStack(stk);           // (2)
    }
    stk->top = NULL;                  // (3)
}

用数组实现的话stk->top=0表示空栈

5、只读接口

  • 只读接口包含:获取栈顶元素、获取栈大小、栈的判空,实现如下:
DataType StackGetTop(struct Stack* stk) {
    return stk->top->data;                 // (1)
}
int StackGetSize(struct Stack* stk) {
    return stk->size;                      // (2)
}

int StackIsEmpty(struct Stack* stk) {
    return !StackGetSize(stk);
}

  • (1)(1) stk->top作为 栈顶指针,它的 数据域 data就是 栈顶元素的值,返回即可;
  • (2)(2) size记录的是 栈元素个数;
  • (3)(3) 当 栈元素 个数为 零 时,栈为空。

四、两种实现的优缺点

1、顺序表实现

  在利用顺序表实现栈时,入栈 和 出栈 的常数时间复杂度低,且 清空栈 操作相比 链表实现 能做到 O(1)O(1),唯一的不足之处是:需要预先申请好空间,而且当空间不够时,需要进行扩容,扩容方式本文未提及,可以参考以下文章:《C/C++ 面试 100 例》(四)vector 扩容策略

2、链表实现

  在利用链表实现栈时,入栈 和 出栈 的常数时间复杂度略高,主要是每插入一个栈元素都需要申请空间,每删除一个栈元素都需要释放空间,且 清空栈 操作是 O(n)O(n) 的,直接将 栈顶指针 置空会导致内存泄漏。好处就是:不需要预先分配空间,且在内存允许范围内,可以一直 入栈,没有顺序表的限制。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
顺序是一种基于数组实现的,它的特点是具有随机存取的特性。顺序的基本运算包括进、出和查看顶元素。进操作将元素插入到顶,出操作将顶元素删除并返回,查看顶元素操作返回顶的元素值,但不修改的状态。 在C语言中,顺序的存储结构可以使用一个一维数组来存放中的元素,同时使用一个指示器top来指示顶的位置。在进行进和出操作时,需要更新top的值,使其指向顶元素。 下面是一种常见的顺序的定义和基本操作的示例代码: ```c // 定义中元素的数据类型 typedef int StackElementType; // 定义顺序的存储结构 #define Stack_Size 100 // 的最大容量 typedef struct { StackElementType elem[Stack_Size]; // 用数组存放中元素 int top; // 顶指针 } SeqStack; // 初始化顺序 void Init_SeqStack(SeqStack *S) { S->top = -1; // 初始时为空,顶指针置为-1 } // 进操作 void Push_SeqStack(SeqStack *S, StackElementType x) { if (S->top == Stack_Size - 1) { printf("已满,无法进"); return; } S->top++; // 顶指针加1 S->elem[S->top] = x; // 将新元素放入顶位置 } // 出操作 StackElementType Pop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空,无法出"); return -1; // 返回一个特殊值表示出错 } StackElementType x = S->elem[S->top]; // 获取顶元素的值 S->top--; // 顶指针减1 return x; // 返回顶元素的值 } // 查看顶元素 StackElementType GetTop_SeqStack(SeqStack *S) { if (S->top == -1) { printf("为空"); return -1; // 返回一个特殊值表示出错 } return S->elem[S->top]; // 返回顶元素的值 } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值