数据结构 链式栈

定义

  • FILO LIFO
  • 先进后出,后进先出
  • 链式栈(链表实现的栈) 顺序栈(顺序表实现的栈)
  • 动态栈(链式栈) 和 静态栈(有内存大小限制,顺序栈)
  • 栈应用非常广泛

顺序静态栈

  • 内存有限
typedef int ElemType;
struct Stack {
    size_t cap; // 容量
    size_t size; // 元素个数
    ElemType *elems;
};

typedef struct Stack* ST;

链栈

  • 动态的
struct Node {
    struct Node *next;
    char elem[];
};

struct Stack {
    size_t elemSize; // 存储的元素类型的字节数
    size_t size;
    struct Node *top; // 指向栈顶元素
};

typedef struct Stack* ST;

比较顺序栈和链式栈

项目顺序栈链式栈
压入/弹出 时间复杂度O(1)
顺序栈如果是动态的可扩容就不能保证时间复杂度为O(1)
O(1)
是否会满不会
  • 用一个数组来表示两个栈,如果要保证内存的利用最大化
    • 一个栈底为0,另一个栈底为n - 1

栈的应用

  • 函数调用的过程的,确实原理就是栈
    • 调用函数即把函数入栈,每次执行的函数都是栈顶的这个函数,执行完成之后出栈

走迷宫

  • 走迷宫

算数表达式求解

  • 算数表达式求解
    • 前缀表达式
    • 中缀表达式
    • 后缀表达式
中缀:(3 + 4) * (5 + 2 * 3) - (3 - 2) / 4;            运算符在操作数中间
后缀:3 4 + 5 2 3 * + * 3 2 - 4 / -

八皇后问题

  • 八皇后问题
国际象棋棋盘8*8       皇后: 横 竖 斜
需要在棋盘上摆放8个皇后,是她们互不威胁

回溯

拆解正整数

  • 拆解正整数
5 = 1 + 1 + 1 + 1 + 1
5 = 1 + 1 + 1 + 2
5 = 1 + 2 + 2
5 = 1 + 4
5 = 2 + 3

7 = 1 + 1 + 1 + 1 + 1 + 1 + 1
7 = 1 + 1 + 1 + 1 + 1 + 2
7 + 1 + 1 + 1 + 1 + 3
7 = 1 + 1 + 1 + 2 + 2
7 = 1 + 1 + 1 + 4
7 = 1 + 1 + 2 + 3
7 = 1 + 2 + 2 + 2
7 = 1 + 1 + 5
7 + 1 + 2 + 4
7 = 1 + 3 + 3
7 = 2 + 2 + 3
7 = 1 + 6
7 = 2 + 5
7 = 3 + 4
bool first = true;
void printNum(ElemType e)
{
    if (first) {
        printf("%d ", e);
        first = false;
    } else {
        printf("+ %d ", e);
    }
}

// 把num分解为n个正整数相加
void decompose(size_t num, size_t orinum, size_t n, ST st)
{
    int top = 0;
    if (n == 1) {
        peek_stack(st, &top);
        if (num >= top) {
            push_stack(st, num);
            first = true;
            printf("%d = ", orinum);
            foreach_stack(st, printNum);
            pop_stack(st, NULL);
            printf("\n");
        }
        return;
    }
    size_t beg = 1;
    if (peek_stack(st, &top) == SUCCESS) {
        beg = top;
    }
    for (; beg < num; ++beg) { // num分解成n>1分。 不直接分 写割除beg 剩下的num-beg分成n - 1份
        push_stack(st, beg);
        decompose(num - beg, orinum, n - 1, st);
        pop_stack(st, NULL);
    }
}

判断是一个序列是否可以作为另一个入栈序列的出栈顺序

  • 判断是一个序列是否可以作为另一个入栈序列的出栈顺序
入栈序列  1 2 3 4 5
问 1 2 3 4 5 可以是入栈顺序的出栈序列
   5 4 3 2 1
   1 2 3 5 3
   3 1 4 2 5 不可以

book is_stack_out_sqe(int inp[], int out[], size_t n);
bool is_stack_out(int in[], int out[], size_t n)
{
    ST st = create_stack(n); // create_stack(sizeof(ElemType));
    int j = 0;
    for (int i = 0; i < n; ++i) {
        push_stack(st, in[i]);
        int elem;
        while (peek_stack(st, &elem) == SUCCESS && elem == out[j]) { // 如果栈顶 == out[j]
            pop_stack(st, NULL);
            ++j;
        }
    }
    bool ret = empty_stack(st);
    destroy_stack(st);
    return ret;
}

链栈实现

结构体定义

struct _SNode {
    struct _SNode *next;
    char elem[];
};

#define _SNODESIZE sizeof(struct _SNode)

struct Stack {
    size_t elemSize; // 元素字节大小
    size_t size; // 元素个数
    struct _SNode *top; // 指向栈顶
};

typedef struct Stack* ST;

基础函数声明

// 创建栈
ST create_stack(size_t elemSize);

// 清空栈
void clear_stack(ST st);

// 销毁
void destroy_stack(ST st);

// 栈中元素个数
size_t size_stack(ST st);

// 栈是否为空
bool empty_stack(ST st);

// 压入栈
int push_stack(ST st, const void *pElem);

// 弹出栈
int pop_stack(ST st, void *pElem);

// 取栈顶
int peek_stack(ST st, void *pElem);

// 迭代
void foreach_stack(ST st, void (*foreach)(const void*));

基础函数实现

创建栈 create_stack
ST create_stack(size_t elemSize) // 传入元素字节大小
{
    ST st = (ST)malloc(sizeof(struct Stack)); // 创建一个空栈
    if (st != NULL) {
        st->elemSize = elemSize; 
        st->size = 0;
        st->top = NULL; // 空栈
    }
    return st;
}
清空栈 clear_stack
void clear_stack(ST st) // 也可以for循环一个一个释放
{
    assert(st != NULL);
    while (!empty_stack(st)) {
        pop_stack(st, NULL);
    }
}
销毁 destroy_stack
void destroy_stack(ST st)
{
    assert(st != NULL);
    clear_stack(st);
    free(st); // 释放栈
}
栈中元素个数 size_stack
size_t size_stack(ST st)
{
    assert(st != NULL);
    return st->size;
}
栈是否为空 empty_stack
bool empty_stack(ST st)
{
    assert(st != NULL);
    return st->top == NULL; // st->size == 0;
}
压入栈 push_stack
int push_stack(ST st, const void *pElem)
{
    assert(st != NULL && pElem != NULL);
    struct _SNode *node = (struct _SNode*)malloc(_SNODESIZE + st->elemSize); // 创建一个栈结点
    if (node == NULL) {
        return FAILURE;
    }
    node->next = st->top; // 压入到栈顶
    st->top = node;
    memcpy(node->elem, pElem, st->elemSize); // 拷贝数据
    ++st->size;
    return SUCCESS;
}
弹出栈 pop_stack
int pop_stack(ST st, void *pElem)
{
    assert(st != NULL);
    if (empty_stack(st)) {
        return FAILURE;
    }
    struct _SNode *node = st->top;
    st->top = node->next; // 从栈顶弹出
    if (pElem != NULL) { // 是否返回删除的元素
        memcpy(pElem, node->elem, st->elemSize);
    }
    free(node);
    --st->size;
    return SUCCESS;
}
取栈顶 peek_stack
int peek_stack(ST st, void *pElem)
{
    assert(st != NULL && pElem != NULL);
    if (empty_stack(st)) {
        return FAILURE;
    }
    memcpy(pElem, st->top->elem, st->elemSize); // 获取栈顶元素
    return SUCCESS;
}
迭代 foreach_stack
void foreach_stack(ST st, void (*foreach)(const void*))
{
    assert(st != NULL && foreach != NULL);
    struct _SNode *node = st->top;
    for (; node != NULL; node = node->next) {
        foreach(node->elem);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值