关于链栈,其实就是单链表的应用,这里要注意的是:
插入链表有两种插入方法,一种是头插,另一种是尾插,也就是在链表表头插入节点,和链表表尾插入节点,你可能会说不都是插入吗,不都是链表节点增加一个吗,能有啥区别?其实区别还蛮大的,1.头插法的时间复杂度O = 1,而尾插法的时间复杂度O = n,造成这个原因的本质原因是链表本身物理实现并不像数组那样是可以按照数组索引(index)对数组的元素进行随机访问,因为链表是我们用指针在堆区开辟的内存并将这些内存用结构体进行人为的设置,结构体内有结构指针,结构指针将堆内的结构内存之间进行了定向链接,注意哦是之间是一对一的关系,而不是一对多,虽然也可以一对多,这样就有点树的感觉了,不过总的来说就是我们定义的结点结构内的结构指针是一个决定了这种结点与结点间是一对一的关系。当然我们这里用头插法,同样的效果放着时间复杂度少的不用,去每次插入在用循环遍历链表到尾部结点再链接生成的新的内存,这不是二傻子吗😂。
还有,关于2.Display函数一定要注意print之后控制指针要移动到下一个节点!!!并且强烈建议用while循环,因为while循环更利于写p != NULL这个循环控制条件,啥?你说for也能写,那是当然,for也能写p != NULL 这个循环控制条件for(;p != NULL;p = p->next)这不就行了吗,但是我不习惯,我一般拿for写那种次数控制循环,啥是次数控制循环,就是for(int number = x;number < condition;number ++)我一看到这个我就知道循环执行codition - x次,尤其是x为0时,这个循环不管怎么样就是执行x次,直截了当。反正不管怎么说条件一定要是结点不为空,不要自作聪明用(int i =链表长度;i>0;i--)因为这样很容易因为出入栈函数忘记进行链表长度++或--而导致不能完全将栈内的数据打印出来!!!
上面也提到了3.出入栈函数忘记进行链表长度++或--这种“高级”遗漏错误,求你了,你做完每步操作不仅要看物理上的实现,再照顾照顾逻辑上的实现好嘛~!
最后王老师说了:学ADT,定义(逻辑结构)、基操、存储(物理)结构这三个闭眼都得会,所以你自己每次写完一个实现,都得问自己,这个操作是干什么的?这个操作所对应的物理结构存和储结构是什么,所写的语法每一步是否都正确的实现了。
//
// main.cpp
// 栈_链栈_不带头节点(王道课本推荐)
//
// Created by 郭宸羽 on 1/8/2022.
//
#include <stdlib.h>
#include <stdio.h>
typedef struct LLNode
{
int data;
struct LLNode *next_p;
}LLNode,*StackOfLL_p;
typedef struct InfomOfStack
{
int stack_size;
int stack_top_position;
StackOfLL_p stack_p;
}InfomOfStack;
int InitialStack(InfomOfStack &stack,int arr[])//
{
//创建链表的第一个节点目的是将外部头指针恒定指向这个头部
LLNode* tem_p = (LLNode*)malloc(sizeof(LLNode));
int i = stack.stack_size-1;//i是数组的index index是从0开始 ∴ 使用数组赋值时下标要-1。
tem_p->data = arr[i];
stack.stack_p = tem_p;
LLNode* con_p = tem_p;
//尾插法创建链表:
for(i = stack.stack_size - 2;i >= 0;i--)//i是数组的index index是从0开始 ∴ 使用数组最后一个元素的下标要=0。
{
tem_p=(LLNode*)malloc(sizeof(LLNode));
tem_p->data = arr[i];//-1 symbol as NULL of data
tem_p->next_p = NULL;
con_p->next_p = tem_p;
con_p = tem_p;
}
stack.stack_top_position = stack.stack_size;//stack_top_position ⇔ stack_p pointer's position of stack
return 1;
}
void Display(InfomOfStack stack)
{
printf("Top:\n");
while (stack.stack_p != NULL)
{
printf("\t[[%d][|]]\n",stack.stack_p->data);
printf("\t v \n");
stack.stack_p = stack.stack_p->next_p;
}
printf("\t[ NULL ]\n\n");
}
int Push(InfomOfStack *stack,int push_data)
{
LLNode *tem =(LLNode*)malloc(sizeof(LLNode));
if (tem == NULL)
{
printf("Stack memory has full,please clean stack memory\n");
}
else
{
tem->data = push_data;//write data
stack->stack_p = tem;//移动栈顶指针
stack->stack_size++;//栈长+1
}
return 1;
}
int Pop(InfomOfStack &stack)
{
if(stack.stack_size == 0)
{
printf("Stack has empty.");
return -1;
}
else
{
LLNode* con_p = stack.stack_p;
int pop_node_data = con_p->data;
stack.stack_p = stack.stack_p->next_p;
free(con_p);
printf("Pop out [%d]\n",pop_node_data);
stack.stack_size--;//易错点!pop完之后一定要让stack_size--,不然后续操作会出大问题!比如查询是否是空栈
}
return 1;
}
int SearchTop(InfomOfStack stack)
{
if(stack.stack_size == 0)
{
printf("Stack has empty.");
return -1;
}
else
{
int top_node_data;
top_node_data = stack.stack_p->data;
printf("Stack top data is:[%d]\n",top_node_data);
}
return 1;
}
int Isfull(InfomOfStack stack)
{
LLNode *tem = (LLNode*)malloc(sizeof(LLNode));
if(tem == NULL)
{
printf("The stack memory is full,please clean it\n");
return -1;
}
else
printf("The stack memory is not full\n");
return 1;
}
int IsEmpty(InfomOfStack stack)
{
if(stack.stack_size == 0)
{
printf("Stack has empty.\n");
return -1;
}
else
printf("The stack is not empty\n");
return 1;
}
int main()
{
InfomOfStack stack1;
stack1.stack_size=8;
int arr[8] ={10,13,16,19,22,25,28,31};
InitialStack(stack1, arr);
Display(stack1);
IsEmpty(stack1);
Isfull(stack1);
Pop(stack1);
Display(stack1);
SearchTop(stack1);
Push(&stack1, -6);
Display(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Pop(stack1);
Display(stack1);
IsEmpty(stack1);
Isfull(stack1);
}