栈的定义

* 栈仅能在线性表的一端进行操作
  栈顶(Top) : 允许操作的一端
   栈底(Bottom) :不允许操作的一端

栈的性质

  

Android 栈顶复用模式 栈顶权限_Android 栈顶复用模式

栈的操作

# 栈的一些常用操作

 *  创建栈

 *  销毁栈
*   清空栈
*   进栈
*   出栈
*   获取栈顶元素
*   获取栈的大小

 栈的顺序存储实现

 

Android 栈顶复用模式 栈顶权限_Stack_02

下面的顺序栈是不能支持结构体的!

现在我们先来实现顺序栈,由于之前我们实现了顺序表,现在代码复用,用其来实现顺序栈

SeqStack.h

Android 栈顶复用模式 栈顶权限_#include_03

 SeqStack.h

SeqStack.c

Android 栈顶复用模式 栈顶权限_#include_03

 SeqStack.c

复用之前的代码

SeqList.c

Android 栈顶复用模式 栈顶权限_#include_03

 SeqList.c

SeqList.h

Android 栈顶复用模式 栈顶权限_#include_03

 SeqList.h

main.c

Android 栈顶复用模式 栈顶权限_Stack_07

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[])
{

    SeqStack* stack = SeqStack_Create(20);
    int a[10];
    int i = 0;

    for (i = 0; i<10; i++)
    {
        a[i] = i;

        SeqStack_Push(stack, a + i);
    }

    printf("Top: %d\n", *(int*)SeqStack_Top(stack));
    printf("Capacity: %d\n", SeqStack_Capacity(stack));
    printf("Length: %d\n", SeqStack_Size(stack));

    while (SeqStack_Size(stack) > 0)
    {
        printf("Pop: %d\n", *(int*)SeqStack_Pop(stack));
    }

    SeqStack_Destroy(stack);

    return 0;
}

Android 栈顶复用模式 栈顶权限_Stack_07

输出结果:

Android 栈顶复用模式 栈顶权限_Stack_09

没有输出?代码?

由于编译器是64位,此时把编译环境换成32位。

输出结果:

Android 栈顶复用模式 栈顶权限_Stack_10

结果如上所示,为什么呢?

看一下表头的定义和顺序表的创建:

Android 栈顶复用模式 栈顶权限_Stack_11

Android 栈顶复用模式 栈顶权限_List_12

 

在32位系统上,指针为4字节。在64位系统上指针为8字节。

在顺序表的创建中,malloc的内存是:表头的结构体[4字节+4字节+指针(4字节或8字节)] + 4字节*capacity

 再看看顺序表的插入函数和get函数:

Android 栈顶复用模式 栈顶权限_#include_13

Android 栈顶复用模式 栈顶权限_List_14

在64位系统中,指针为8字节,在插入函数中,node强转成TseqListNode(unsigned int)赋值给sList->node[i](指针)。指针的偏移是8字节。
顾把一个8字节的指针强转成4字节,发生指针截断,这里就会出错。
改进代码为:
把SeqList.c文件中的typedef unsigned int TSeqListNode;
替换为:

Android 栈顶复用模式 栈顶权限_List_15

这样如果编译器为64位,则开启64位的宏,如果编译器为32位,则开启32位的宏。 

栈的链式实现:

链式栈是可以支持结构体的,但是要求和链式表一样需要包含特定的头,为了后续的历程复用,下面不使用结构体类型入栈操作。

 eg:

LinkStack.h

Android 栈顶复用模式 栈顶权限_Stack_07

#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_

//抽象数据类型
typedef void LinkStack;

//创建顺序栈
LinkStack* LinkStack_Create();

//销毁
void LinkStack_Destroy(LinkStack* stack);

//清除
void LinkStack_Clear(LinkStack* stack);

//压栈
int LinkStack_Push(LinkStack* stack, void* item);

//出栈,弹出
void* LinkStack_Pop(LinkStack* stack);

//栈顶
void* LinkStack_Top(LinkStack* stack);

//栈大小
int LinkStack_Size(LinkStack* stack);

#endif

Android 栈顶复用模式 栈顶权限_Stack_07

源文件:LinkStack.c

Android 栈顶复用模式 栈顶权限_Stack_07

#include <malloc.h>
#include "LinkStack.h"
#include "LinkList.h"

typedef struct _tag_LinkStackNode
{
    LinkListNode header;
    void* item;
} TLinkStackNode;

LinkStack* LinkStack_Create()
{
    return LinkList_Create();
}

void LinkStack_Destroy(LinkStack* stack)
{
    LinkStack_Clear(stack);
    LinkList_Destroy(stack);
}

void LinkStack_Clear(LinkStack* stack)
{
    while( LinkStack_Size(stack) > 0 )
    {
        LinkStack_Pop(stack);
    }
}

int LinkStack_Push(LinkStack* stack, void* item)
{
    TLinkStackNode* node = (TLinkStackNode*)malloc(sizeof(TLinkStackNode));
    int ret = (node != NULL) && (item != NULL);
    
    if( ret )
    {
        node->item = item;
        
        ret  = LinkList_Insert(stack, (LinkListNode*)node, 0);
    }
    
    if( !ret )
    {
        free(node);
    }
    
    return ret;
}

void* LinkStack_Pop(LinkStack* stack)
{
    TLinkStackNode* node = (TLinkStackNode*)LinkList_Delete(stack, 0);
    void* ret = NULL;
    
    if( node != NULL )
    {
        ret = node->item;
        
        free(node);
    }
    
    return ret;
}

void* LinkStack_Top(LinkStack* stack)
{
    TLinkStackNode* node = (TLinkStackNode*)LinkList_Get(stack, 0);
    void* ret = NULL;
    
    if( node != NULL )
    {
        ret = node->item;
    }
    
    return ret;
}

int LinkStack_Size(LinkStack* stack)
{
    return LinkList_Length(stack);
}

Android 栈顶复用模式 栈顶权限_Stack_07

注意,上面的push操作时插入到链表首的,这样更快一些,不用循环到链表尾部。

链式栈的清除不能直接调用链式表的清除,否则产生内存泄露,这里主要是为了之后的栈的例子,所以使用基本类型元素入栈,如果实现成可以支持结构体入栈的形式,直接调用链式表的清除函数即可,这个留给大家练手,可参考链式表的实现。

链式栈的销毁是在调用了栈的清除函数之后再次调用链式表的销毁构成的,其他的复用没有什么变化。

main.c

Android 栈顶复用模式 栈顶权限_Stack_07

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) 
{
    LinkStack* stack = LinkStack_Create();
    int a[10];
    int i = 0;
    
    for(i=0; i<10; i++)
    {
        a[i] = i;
        
        LinkStack_Push(stack, a + i);
    }
    
    printf("Top: %d\n", *(int*)LinkStack_Top(stack));
    printf("Length: %d\n", LinkStack_Size(stack));
    
    while( LinkStack_Size(stack) > 0 )
    {
        printf("Pop: %d\n", *(int*)LinkStack_Pop(stack));
    }
    
    LinkStack_Destroy(stack);
    
    return 0;
}

Android 栈顶复用模式 栈顶权限_Stack_07

输出结果和顺序栈是一样的。