栈操作原则
使用栈操作数据,必须遵循“先入后出”的原则;
栈操作之链栈
链栈是用链表实现栈的存储结构,链表头部作为栈顶,链表尾部为栈底(单链表);
入栈
写入数据时,实际是对链表做“头插”操作,空链表时,头指针head指向null;新进数据插入链表头部,头指针head指向当前链表头部;以此类推,这种操作即为入栈(压栈);
出栈
读出数据时,实际是删除当前链表的头部(首元节点),将头指针head指向新的链表头部(原首元节点的下一节点,成为当前首元节点),以此类推,这种操作即为出栈(弹栈);
代码实现
在这段代码中,主要实现:
1.创建链表数据结构,初始化为空链表;
2.入栈操作,压入8个数据;
3.出栈操作,弹出2个数据,栈中剩余最先入栈的6个数据;
4.打印各个过程的情况;
5.在CMD中运行查看结果;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 创建链表的数据结构
typedef struct list_stack
{
int data;
struct list_stack *next;
} list_stack;
// 链栈入栈操作,head为当前链栈栈顶指针,val为入栈的值
list_stack *push(list_stack *head, int val)
{
// 创建新节点,并分配内存
list_stack *p = (list_stack *)malloc(sizeof(list_stack));
p->data = val;
// 建立当前节点与头指针head之前所指节点的关系(头插)
p->next = head;
// 使头指针head指向当前新插入节点
head = p;
printf("push elem %d\r\n", head->data);
printf("current head elem is : %d\r\n", head->data);
return head;
}
list_stack *pop(list_stack *head)
{
// 如果head指向不为空,可进行出栈操作
if (head != NULL)
{
// 头指针head当前指向表头节点,定义指针p指向表头节点
list_stack *p = head;
// 使头指针head指向下一个节点,即删除head之前所指节点(单链表)
head = head->next;
//打印出栈元素,即被删除节点的值(p所指节点)
printf("pop elem %d\r\n", p->data);
//释放内存
free(p);
//如果head指向非空,打印当前head所指节点的值
if(head != NULL)
{
printf("current head elem is : %d\r\n", head->data);
}
//如果head指向为空,打印提示信息
else
{
printf("pop fail! no more elem!\r\n");
}
}
else
{
printf("stack is empty!\r\n");
}
return head;
}
// 正向遍历链表,打印出链表节点值
void show_list_in_order(list_stack *head)
{
// 链表不为空,执行遍历
if (head != NULL)
{
// head指向链表头部,初始化使p从链表头部开始
list_stack *p = head;
printf("list stack from head to tail is:\r\n");
while (p->next != NULL)
{
printf("%d\r\n", p->data);
p = p->next;
}
// 打印出链表尾部节点值
printf("%d\r\n", p->data);
}
else
{
printf("print fail! stack is empty!\r\n");
}
}
int main(void)
{
int i = 0;
int j = 0;
// 初始化头指针head指向为空,即链表为空
list_stack *head = NULL;
// 压栈操作,并打印栈内元素值
printf("push stack:\r\n");
for (i = 0; i < 8; i++)
{
head = push(head, i);
}
show_list_in_order(head);
// 出栈操作,并打印栈内元素值
printf("\npop stack:\r\n");
for (j = 0; j < 2; j++)
{
head = pop(head);
}
show_list_in_order(head);
}
CMD运行结果