栈
我们可以通过顺序存储的方式来实现栈逻辑,这种栈叫做顺序栈,也可以通过链式存储的方式实现,这种栈叫做链式栈,存储结构的异同不影响栈先进后出的特性
顺序栈
顺序栈的实现主要就是定义一块连续内存存放栈元素,为了方便管理创建一个整形数据代表栈顶元素在此连续内存中的偏移,这样可以很方便的知道此栈的状态和栈顶元素位置,便于压栈和出栈,我们将这些元素存放在同一个管理结构体中,根据我们的思路,顺序栈可以用以下代码来表示:
cpp
struct sequent_stack
{
int *stack; //指向用以存放栈元素的连续内存
int size; //保存该数据栈的总大小
int top; //表示栈顶元素的偏移量
};
初始化
有了结构体我们就要考虑该如何初始化这个栈,首先将stack指向的内存清零,其次将top置为-1并规定-1为空栈,这么做的好处是,压栈第一个元素后top+1就成了0,第一个元素偏移为0
cpp
struct sequent_stack *stack_init(int size)
{
struct sequent_stack *s;
s = malloc(sizeof(struct sequent_stack));
if(s != NULL)
{
s->stack = calloc(size,sizeof(int));
//CALLOC函数相比于malloc的区别在于会在分配之后将内存设置为0
s->size = size;
s->top = -1;
}
return s;
}
有了初始化的栈,接下来就是编写一些基本操作
压栈
压栈的第一步要判断栈是否已满,如果未满则将元素置于栈顶,已满则进行扩充或者错误退出:
cpp
bool stack_full(struct sequent_stack *s)
{
return s->top >= s->size-1;
}
bool push(struct sequent_stack *s,int data)
{
if(stack_full(s))
return false;
s->top++;
s->stack[s->top] = data;
return true;
}
出栈
出栈中因为要返回bool值表示是否成功,所以要获取一个参数来存放出栈的元素,其次在出栈前要先判断是否为空栈
cpp
bool stack_empty(struct sequent_stack *s)
{
return s->top == -1;
}
bool pop(struct sequent_stack *s,int *p)
{
if(stack_empty(s))
return false;
*p = s->stack[s->top];
s->top--;
return true;
}
结合上面的操作我们可以使用栈操作进行十进制转8进制的操作
cpp
int main(int argc, char const *argv[])
{
struct sequent_stack *s;
s = stack_init(10);
int n;
scanf("%d",&n);
while(n>0)
{
push(s,n%8);
n /= 8;
}
int m;
while(!stack_empty(s))
{
pop(s,&m);
printf("%d",m);
}
printf("\n");
return 0;
}
链式栈
对于链式栈来说以上那些基本操作也是需要实现的,由此我们进行
初始化
首先定义管理结构体和节点结构体
cpp
struct node //栈节点结构体
{
int data;
struct node *next;
};
struct linked_stack //管理结构体
{
int size;
struct node *top; //指向栈顶节点
};
再根据管理结构体进行初始化
cpp
struct linked_stack *init_stack (void)
{
struct linked_stack *s;
s = malloc(sizeof(struct linked_stack));
if(s != NULL)
{
s->size = 0;
s->top = NULL;
}
return s;
}
压栈
cpp
//创建新节点
struct node *new_node(int data)
{
struct node *new;
new = malloc(sizeof(struct node));
if(s != NULL)
{
new->data = data;
new->next = NULL;
}
return new;
}
//压栈
bool push(struct linked_stack *s,struct node *new)
{
if (s == NULL || new == NULL)
return false;
new->next = s->top;
s->top = new;
s->size++;
return true;
}
出栈
cpp
bool stack_empty(struct linked_stack *s)
{
return s->size == 0;
}
bool pop(struct linked_stack *s,int *p)
{
if(s == NULL || p == NULL || stack_empty(s))
return false;
*p = s->top->data;
s->top = s->top->next;
s->size--;
return true;
}
汉诺塔
根据链栈,写出一个汉诺塔问题的递归函数
cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct node //栈节点结构体
{
int data;
struct node *next;
};
struct linked_stack //管理结构体
{
int size;
struct node *top; //指向栈顶节点
};
struct linked_stack *init_stack (void)
{
struct linked_stack *s;
s = malloc(sizeof(struct linked_stack));
if(s != NULL)
{
s->size = 0;
s->top = NULL;
}
return s;
}
//创建新节点
struct node *new_node(int data)
{
struct node *new;
new = malloc(sizeof(struct node));
if(new != NULL)
{
new->data = data;
new->next = NULL;
}
return new;
}
//压栈
bool push(struct linked_stack *s,struct node *new)
{
if (s == NULL || new == NULL)
return false;
new->next = s->top;
s->top = new;
s->size++;
return true;
}
bool stack_empty(struct linked_stack *s)
{
return s->size == 0;
}
bool pop(struct linked_stack *s,struct node **p)
{
if(s == NULL || p == NULL || stack_empty(s))
return false;
*p = s->top;
s->top = s->top->next;
(*p)->next = NULL;
s->size--;
return true;
}
void show(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C)
{
int maxlen,len;
maxlen = A->size > B->size ? A->size : B->size;
maxlen = maxlen > C->size ? maxlen : C->size;
len = maxlen;
struct node *t1 = A->top;
struct node *t2 = B->top;
struct node *t3 = C->top;
int i;
for (i = 0; i < maxlen; i++)
{
if(t1 != NULL && len <= A->size)
{
printf("%d",t1->data);
t1 = t1->next;
}
printf("\t");
if(t2 != NULL && len <= B->size)
{
printf("%d",t2->data);
t2 = t2->next;
}
printf("\t");
if(t3 != NULL && len <= C->size)
{
printf("%d",t3->data);
t3 = t3->next;
}
printf("\t");
printf("\n");
len--;
}
printf("A\tB\tC\n");
printf("-----------------\n");
}
void hano(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C,int n)
{
if(n <= 0)
return;
struct node *tmp;
hano(A,C,B,n-1); //将n-1块从A借助C移向B
getchar(); //每回车一次进行一步
show(A,B,C);
pop(A,&tmp);
push(C,tmp); //将A最下面一块移动到C
hano(B,A,C,n-1); //将n-1块从B借助A移向C
}
int main(int argc, char const *argv[])
{
struct linked_stack *A = init_stack();
struct linked_stack *B = init_stack();
struct linked_stack *C = init_stack();
int hanois = 0;
scanf("%d",&hanois);
int i;
for (i = 0; i < hanois; i++)
{
struct node *new = new_node(hanois-i); //将汉诺塔中的块放入栈A(柱A)
push(A,new);
}
hano(A,B,C,hanois);
show(A,B,C);
return 0;
}