3.1.3 栈的链式存储实现
约 40 分钟
3.1.3 链栈:让链首承担栈顶
链栈通常把单链表首结点作为栈顶,因为在首部插入和删除都不需要遍历。若不带头结点,top==NULL 表示空栈:
typedef struct Node{ int data; struct Node *next; } Node;
int push(Node **top,int x){ Node *p=malloc(sizeof *p); if(!p)return 0;
p->data=x; p->next=*top; *top=p; return 1; }
int pop(Node **top,int *x){ if(!*top)return 0; Node *p=*top;
*x=p->data; *top=p->next; free(p); return 1; }
Node **top 使函数能够修改调用者保存的栈顶指针。若只传 Node *top,更新停留在形参副本里。正常情况下链栈没有固定容量上限,但分配失败仍须处理。
手工推演:栈 top -> 30 -> 20 -> 10 弹出时,先用 p 保存 30,再令 top 指向 20,最后释放 30。若先释放 30 再读 p->next,发生释放后访问;若只移动 top 不释放,则内存泄漏。
带头结点也可实现,空条件改为 head->next==NULL,入栈位置仍是头结点之后。头结点不算栈内元素。顺序栈局部性更好且无逐结点分配开销;链栈适合规模难预测的情况。
错解反馈:把链尾作为栈顶会使单链表出栈需要找前驱,退化为 ;声称链栈永不溢出,忽略系统内存耗尽;弹出后不更新外部头指针,表面返回成功但栈状态未变。
迁移题:连续入栈 4、5、6 后弹出两次,返回值与最终链是什么?答案返回 6、5,最终 top->4->NULL。独立验收:能说明双重指针的必要性,并用地址箭头逐句推演一次入栈和一次出栈。
小纸条
编程:链栈弹出唯一结点后,top应为何值?还必须做什么?
登录 后可看答案
Practice
本课练习
先独立作答再提交;编程题会在隔离沙箱中真实编译、运行并对拍。
本课练习正在补齐,暂不应标记为完成。