数据结构--链式栈、顺序栈的基本实现与简单应用:进制转换

一、栈的基本概念:

1、栈(Stack),是基本数据结构中比较重要的一种,其遵循的基本原则是:先进后出(First In Last Out,FILO);我们编程时操作系统为函数参数压栈,其系统内核栈的实现就是基于该数据结构。我们以顺序栈来介绍起基本结构。下图为一个基本的栈的结构(这是一个顺序栈):

这里写图片描述

我们所建的栈以及内核中实现,在结构上其实并非该图所示,因为内存地址从高到低分配,所以栈应该是“口朝下”的,但是为了方便理解(现实中我们认为“底”应该在下面)所以我们用这种图来表示。栈有两个指针来标识其“头”与“尾”,其中,栈的高地址指针叫栈底指针(pBottom),栈的低地址指针叫做栈顶指针(pTop)。数据存入栈中称为数据入栈(或者压栈),数据从栈中取出来称为出栈(或者推栈)。在该图中,入栈的顺序是num1->num2->num3->num4,而出栈顺序是num4->num3->num2->num1;最先入栈的数据最后才能被推栈出来,所以叫先入后出式存储结构。

2、关于栈的口朝下还是口朝上问题,我们用一个小例子来测试一下:

# include<stdio.h>

int add(int x,int y)/*函数传参压栈顺序为从右向左*/
{
    printf("address_x = %p\naddress_y = %p\n",&x,&y);
    return (x+y);
}
int main(void)
{
    int sum = add(3,5);
    printf("sum = %d\n",sum);
}

我们将x和y的地址打印输出:

这里写图片描述

由于y先压栈,x后压栈,我们打印输出的结果显示,address_y为高地址,而address_x为低地址,所以由此我们可以得出,操作系统在栈的实现中是高地址为栈底,低地址为栈顶。因此我们还是将栈的结构图再翻过来吧:

这里写图片描述

3、满“栈”与空“栈”,听到这两个名字,也许你会认为,“满栈”就是栈已经存满了数据,而“空栈”则是栈中没有数据,那你就大错特错了。首先,我们画出两张栈的结构图:

这里写图片描述

在该图中,我们发现满栈与空栈中都没有存放数据,但是满栈pTop指针并没有指向第一块栈内存,而空栈的pTop指针指向了第一块栈内存。所以,这就是满栈与空栈的区别:
满栈:满栈的栈顶指针指向栈顶数据(没有数据时,和pBottom都指向NULL),对于满栈的操作则是,先移动栈顶指针,然后在栈顶指针所指向的内存中存入数据;
空栈:空栈的栈顶指针指向一块空内存(没有数据时,pBottom指向NULL,pTop不指向NULL),该内存的上一块内存才是最顶层的数据,对于空栈的操作则是,先在栈顶指针所指向的内存中存入数据,然后移动栈顶指针;
今天我们采用满栈来进行一系列操作。

二、顺序栈(借助数组)的实现与操作:

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

# define MAX_STACK_LEN 5    /*栈最大元素个数*/

/*顺序栈的结构体定义*/
typedef struct stack_arr
{
    int data[MAX_STACK_LEN];
    int top;//数组下标作为栈顶指针,而栈底指针不需要指定
}STACKARR;

void init_stack(STACKARR *);//初始化栈
int empty_stack(STACKARR * pS);//栈判空
int full_stack(STACKARR * pS);//栈判满
void push_stack(STACKARR *);//压栈
void traverse_stack(STACKARR *);//遍历
void pop_stack(STACKARR *);//出栈
void clear_stack(STACKARR * pS);//栈清空

int main(void)
{
    STACKARR Stack;/*创建了一个含有MAX_STACK_LEN个数据的顺序栈*/
    init_stack(&Stack);/*对该栈初始化*/

    push_stack(&Stack);
    printf("压栈完毕,栈中元素依次为(栈顶->栈底):\n");
    traverse_stack(&Stack);

    pop_stack(&Stack);
    printf("出栈完毕,栈中元素依次为(栈顶->栈底):\n");
    traverse_stack(&Stack);

    clear_stack(&Stack);
    printf("栈已清空");
    traverse_stack(&Stack);

    return 0;
}

void init_stack(STACKARR * pS)
{
    memset(pS->data, 0, sizeof(pS->data));
    pS->top = -1;/*满栈让栈定指针初始化在第一个地址的前一个地址*/
}

int empty_stack(STACKARR * pS)
{
    return ( (pS->top == - 1) ? (-1) : (0) );
}

int full_stack(STACKARR * pS)
{
    return ( (pS->top == MAX_STACK_LEN - 1) ? (-1) : (0) );
}

void push_stack(STACKARR * pS)
{
    int num = 0;
    int choose = 0;
    while(1){
        if(full_stack(pS) == -1){
            printf("栈已满,不能压栈!\n");
            exit(EXIT_FAILURE);
        }
        printf("请输入要压栈的数据:");
        scanf("%d",&num);
        pS->top++;/*满栈先移动指针,再存储*/
        pS->data[pS->top] = num;    
        printf("入栈成功,继续入栈?(继续输入1,结束输入2):");
        scanf("%d",&choose);
        if(choose != 1){
            break;
        }
    }
}

void traverse_stack(STACKARR * pS)
{
    int i = 0;
    if(empty_stack(pS) == -1){
        printf("栈为空!\n");
        exit(EXIT_FAILURE);
    }
    /*从栈顶部开始遍历*/
    for(i = pS->top; i >= 0; i-- ){
        printf("%d\t",pS->data[i]);
    }
    printf("\n");
}

void pop_stack(STACKARR * pS)
{
    int choose = 0;
    while(1){
        if(empty_stack(pS) == -1){
            printf("栈为空!\n");
            exit(EXIT_FAILURE);
        }
        printf("出栈元素为:%d\n",pS->data[pS->top]);/*先出栈栈顶指针再自减1*/
        pS->top--;
        printf("出栈成功,继续出栈?(继续输入1,结束输入2):");
        scanf("%d",&choose);
        if(choose != 1){
            break;
        }
    }
}

void clear_stack(STACKARR * pS)
{
    memset(pS->data, 0, sizeof(pS->data));
    pS->top = -1;
}

测试结果:
这里写图片描述

三、链式栈(借助链表)的实现与操作:

我们今天使用双向链表来实现(单向链表更简单,但是双向链表的复杂会使我们对栈这种结构认识更加清晰),基本结构如下:

这里写图片描述

测试代码:

/**
    *2016年12月13日10:52:39
    *Create Stack of Link
**/
#include <stdio.h>
#include <stdlib.h>

#ifndef bool
#define bool int

typedef struct stack_node{
    int data;
    struct stack_node * pDown;
    struct stack_node * pUp;
}STACKNODE;/*栈的节点结构体*/

typedef struct stack_link{
    STACKNODE * pTop;
    STACKNODE * pBottom;
}STACKLINK; /*栈顶指针与栈底指针结构体*/

enum{false,true};

void init_stack(STACKLINK *);/*初始化*/
void push_stack(STACKLINK *);/*压栈*/
void travsal_stack(STACKLINK *);/*遍历*/
void pop_stack(STACKLINK *);/*出栈*/
bool empty_stack(STACKNODE * pS);/*栈判空,链式栈不存在满栈情况,无需判满*/

int main(void)
{
    STACKLINK Stack;
    init_stack(&Stack);/*初始化栈*/

    push_stack(&Stack);/*压栈*/
    travsal_stack(&Stack);/*从栈顶开始遍历*/

    pop_stack(&Stack);/*出栈*/
    travsal_stack(&Stack);

    return 0;
}

void init_stack(STACKLINK * pS)
{
    pS->pTop = NULL;
    pS->pBottom = NULL;/*初始化将栈顶指针与栈底指针均赋空*/
    printf("初始化成功!\n");
}

void push_stack(STACKLINK * pS)
{
    int num, choose;
    STACKNODE * pNew = NULL;
    while(1){
        printf("请输入压栈数据:");
        scanf("%d",&num);

        pNew = (STACKNODE *)malloc(sizeof(STACKNODE));
        if(NULL == pNew){
            printf("内存分配失败!\n");
            exit(EXIT_FAILURE);
        }
        pNew->data = num;
        pNew->pUp = NULL;
        pNew->pDown = NULL;/*入栈元素初始化*/

        if(empty_stack(pS->pTop) == -1){/*栈为空*/
            pS->pBottom = pS->pTop = pNew;
        }
        else{/*栈不为空*/
            pS->pTop->pUp = pNew;/*上一个为新元素*/
            pNew->pDown = pS->pTop;/*新元素的下一个为原有栈顶元素*/
            pS->pTop = pNew;/*栈顶指针向上移到*/
        }

        printf("继续压栈?(继续请选1,结束请选2):");
        scanf("%d",&choose);
        if(choose != 1){
            break;
        }
    }
}

void travsal_stack(STACKLINK * pS)
{
    STACKNODE * pMove;
    pMove = pS->pTop;

    while(1){
        if(pMove == NULL){
            break;
        }
        printf("%d\t",pMove->data);
        pMove = pMove->pDown;
    }
    printf("\n");
}

void pop_stack(STACKLINK * pS)
{
    STACKNODE * pDelete;
    int choose = 0;
    while(1){
        pDelete = pS->pTop;
        if(empty_stack(pDelete) == -1){
            printf("栈为空,出栈失败!\n");
            exit(EXIT_FAILURE);
        }
        printf("出栈元素为:%d\n",pDelete->data);
        pS->pTop = pDelete->pDown;/*栈顶指针向下移*/
        if(pS->pTop != NULL)/*注意当pS->pTop为空,即栈为空时,无pS->pTop->pUp,若不判断会出现段错误*/
            pS->pTop->pUp = NULL;/*栈顶指针的上一个(前驱指针)为空*/
        free(pDelete);

        printf("继续出栈?(继续请选1,结束请选2):");
        scanf("%d",&choose);
        if(choose != 1){
            break;
        }
    }
}

bool empty_stack(STACKNODE * pN)
{
    return ((pN == NULL) ? -1 : 0);
}
#endif

四、栈的应用——借助栈实现进制转换:

/*用数组创建一个栈*/
# include<stdio.h>
# include<string.h>
# include<stdlib.h>

# define SIZE 32

typedef struct Stack{
    int sta_arr[SIZE];
    int top;
}STACK;

void init_stack(STACK *);

void init_stack(STACK * pS)
{
    memset(pS->sta_arr, 0, sizeof(pS->sta_arr));
    pS->top = -1;
}

int is_full(STACK * pS)
{
    return ((pS->top == SIZE-1) ? 0 : 1);
}
int is_empty(STACK * pS)
{
    return ((pS->top == -1) ? 0 : 1);
}

void input_stack(STACK * pS, int value)
{
    if(is_full(pS)){
        pS->top++;
        pS->sta_arr[pS->top] = value;
    }
}
void output_stack(STACK * pS)
{
    if(is_empty(pS))
        printf("%d",(pS->sta_arr)[pS->top]);
}

void invert(STACK * pS, int value, int type)
{
    int tmp,num = value;
    init_stack(pS);
    while(num)
    {
        /*进制转化:取余之后压栈,再取整,低位就在栈底,自然最后输出*/
        tmp = num % type;   
        input_stack(pS,tmp);    
        num = num / type;
    }
    /*出栈*/
    while(pS->top != -1)
    {
        output_stack(pS);
        pS->top--;
    }
    printf("\n");

}
int main (void)
{
    STACK S;
    int value, type;
    init_stack(&S);
    printf("请输入你要转换的十进制数字:\n");
    scanf("%d",&value);
    printf("请选择你要转换成的进制格式(2~9,如:2代表二进制):\n");
    scanf("%d",&type);
    if(type > 9 || type < 2){
        printf("选择的进制格式暂时无法处理!\n");
        exit(EXIT_FAILURE);
    }
    invert(&S,value,type);
    return 0;
}

测试:

这里写图片描述

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值