数据结构:通用栈

栈 stack

栈的特点是先入后出 和链表的共同点是插入/删除节点容易
相较之下栈还更简洁一些 因为栈不需要遍历 插入和删除节点都以栈顶节点为基准
不需要像链表那样实现随机访问.

侵入式结构

前面讨论过链表的侵入式实现,实现通用的数据结构
http://blog.csdn.net/qq_21358401/article/details/79266329

栈也同样可以用侵入式的结构实现:
struct stack {
    struct statck *next; // pointer to next node of stack
};

首先栈需要一个栈顶节点
struct stack top;

初始化栈 #define INIT_STACK(top) {top->next = NULL;}

从栈顶插入节点
static inline void stack_push(struct stack *top, struct stack *new_node) {
    assert(top != NULL);
    assert(new_node != NULL);

    new_node->next = top->next; // 新节点指向原栈顶的next节点
    top->next = new_node; // 新节点作为栈顶的next节点
}

从栈顶获取节点并删除
static inline struct statck * _stack_pop(struct stack *top) {
    assert(top != NULL);
    struct stack *tmp = top->next;

    if (top->next != NULL) {
        top->next = tmp->next; // 返回栈顶的next节点
    } else {
        return NULL;
    }

    return tmp;
}

有一个问题在于返回的是struct stack节点的地址
但侵入式的数据结构 需要包在stack外的数据的地址
所以还需要一个宏来返回真正的包装结构的节点
#define list_entry(ptr,type,member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

#define stack_pop(top,type,member) list_entry(_stack_pop(top),type,member)
list_entry在链表中已经分析过了 根据偏移量获取包装结构的地址
stack_pop则根据此返回包装结构

判断栈是否为空 = 判断栈顶的next节点是否存在
static inline int stack_empty(struct stack *top) {
    return top->next == NULL;
}

示例代码

//
// Created by mac on 2018/2/22.
//

#ifndef CODINGUTILS_STACK_H
#define CODINGUTILS_STACK_H

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

struct stack {
    struct stack *next;
};

#define INIT_STACK(top) {(top)->next = NULL;}
#define list_entry(ptr,type,member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

static inline void stack_push(struct stack *top, struct stack *new_node) {
    assert(top != NULL);
    assert(new_node != NULL);

    new_node->next = top->next;
    top->next = new_node;
}

static inline struct statck * _stack_pop(struct stack *top) {
    assert(top != NULL);
    struct stack *tmp = top->next;

    if (top->next != NULL) {
        top->next = tmp->next;
    } else {
        return NULL;
    }

    return tmp;
}

static inline int stack_empty(struct stack *top) {
    return top->next == NULL;
}

#define stack_pop(top,type,member) list_entry(_stack_pop(top),type,member)

#endif //CODINGUTILS_STACK_H


//
// Created by mac on 2018/2/22.
//

#include "stack.h"

#define log(fmt,...)\
    do {\
        printf(fmt,##__VA_ARGS__);\
        printf("\n");\
    } while (0)

struct stack_node {
    struct stack node;
    int val;
};

int main() {
    log("stack test");

    struct stack top;
    INIT_STACK(&top);

    int i = 0;
    for (i = 0; i < 5; i++) {
        struct stack_node *tmp = NULL;
        tmp = malloc(sizeof(struct stack_node));
        if (!tmp) {
            log("failed to malloc stack node");
            return -1;
        }

        tmp->val = i;
        stack_push(&top, &tmp->node);
        log("push node to stack val:%d", tmp->val);
    }

    while (!stack_empty(&top)) {
        struct stack_node *val = NULL;
        val = stack_pop(&top, struct stack_node, node);
        log("val:%d", val->val);
        free(val);
    }


    return 0;
}

github repo路径
https://github.com/sliver-chen/codingutil/tree/master/data_struct/stack
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值