链式存储结构最大的好处就是没有空间的限制,可以通过指针指向将结点像以链的形式把结点链接,我们熟悉的线性表就有链式存储结构。
当然,栈同样有链式存储结构,栈的链式存储结构,简称链栈。
从图片可以看到,和单链表很像,拥有一个头指针top,又称作栈顶指针,所以此时就不再需要单链表里面的头结点了。
对于链栈来说,基本不存在栈满的情况,除非计算机内存已经没有了可使用的空间,如果真的存在,那么计算机系统已经面临着即将死机崩溃的情况,而不是这个链栈是否溢出的问题了。
对于空栈来说,链表的定义是头指针指向NULL,而链栈是top=NULL
链栈的结构定义:
1 /*链栈的定义需要用到两个结构体*/
2 typedef struct StackNode{ //单链表节点类型
3 int data;
4 StackNode* next;
5
6 }StrackNode;
7 typedef struct StackNode *LinkStackPtr;
8
9 typedef struct { //栈
10
11 LinkStackPtr top; //栈底指针
12 int count;
13
14 }LinkStact;
进栈操作
/*入栈*/
void PushStack(LinkStact *s,int e){ //这边栈应该传地址
LinkStackPtr a =(StackNode*)malloc(sizeof(StackNode)); //新的节点
a->data = e;
a->next = s->top; //把当前的栈顶元素赋值给新结点的直接后继
s->top =a; /* 将新的结点s赋值给栈顶指针 */
s->count++;
}
这里重新回忆一下参数传参的两种方式:传值、传地址。
传值:传值无非就是实参拷贝传递给形参,单向传递(实参->形参),二者中间做了一个拷贝动作,即两者的实际地址不同了,所以对任何一方的操作都不会影响到另一方。
传地址:形参和实参是同一个变量,即使用相同的内存空间,二者有相同的地址,修改任意一方都将相互影响。
出栈操作
/*出栈,并返回栈顶元素*/
int PopStack(LinkStact *s){
int top;
LinkStackPtr p;
p = s->top; /* 将栈顶结点赋值给p */
if(p ==NULL)
return -1;
top = p->data;
s->top=s->top->next; /* 使得栈顶指针下移一位,指向后一结点,即指向新的栈顶 */
free(p); //释放内存
s->count--; //长度减一
return top;
}
使用栈时确记要记得给栈初始化
1 /*初始化一个空栈*/
2 int InitStack(LinkStact *s){
3 s->top = (StackNode *)malloc(sizeof(StackNode));
4 if(!s->top)
5 return 0;
6 s->top=NULL;
7 s->count=0;
8 return 1;
9 }
遍历栈操作
1 /*遍历栈*/
2 void StackTraverse(LinkStact s){
3 LinkStackPtr p;
4 p=s.top; //指针指向栈顶
5 while(p) //当栈不为空时
6 {
7 printf("%d ",p->data);
8 p =p->next;
9 }
10 }
清空栈操作
1 /*清空栈*/
2 void ClearStack(LinkStact *s){
3
4 LinkStackPtr p,q;
5 p = s->top; //取栈顶
6 while(p){
7 q=p;
8 p=p->next;
9 free(q);
10 }
11 s->count=0;
12 }
其他的操作见代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 /*链栈的定义需要用到两个结构体*/ 5 typedef struct StackNode{ //单链表节点类型 6 int data; 7 StackNode* next; 8 9 }StrackNode; 10 typedef struct StackNode *LinkStackPtr; 11 12 typedef struct { //栈 13 14 LinkStackPtr top; //栈底指针 15 int count; 16 17 }LinkStact; 18 19 /*初始化一个空栈*/ 20 int InitStack(LinkStact *s){ 21 s->top = (StackNode *)malloc(sizeof(StackNode)); 22 if(!s->top) 23 return 0; 24 s->top=NULL; 25 s->count=0; 26 return 1; 27 } 28 29 /*清空栈*/ 30 void ClearStack(LinkStact *s){ 31 32 LinkStackPtr p,q; 33 p = s->top; //取栈顶 34 while(p){ 35 q=p; 36 p=p->next; 37 free(q); 38 } 39 s->count=0; 40 } 41 42 /*判断是否为空栈,为空返回0,否则返回1*/ 43 int StackEmpty(LinkStact *s){ 44 if(s->count==0) 45 return 1; 46 else 47 return 0; 48 } 49 50 /*入栈*/ 51 void PushStack(LinkStact *s,int e){ //这边栈应该传地址 52 53 LinkStackPtr a =(StackNode*)malloc(sizeof(StackNode)); //新的节点 54 a->data = e; 55 a->next = s->top; //把当前的栈顶元素赋值给新结点的直接后继 56 s->top =a; /* 将新的结点s赋值给栈顶指针 */ 57 s->count++; 58 } 59 60 /*出栈,并返回栈顶元素*/ 61 int PopStack(LinkStact *s){ 62 int top; 63 LinkStackPtr p; 64 p = s->top; /* 将栈顶结点赋值给p */ 65 if(p ==NULL) 66 return -1; 67 top = p->data; 68 s->top=s->top->next; /* 使得栈顶指针下移一位,指向后一结点,即指向新的栈顶 */ 69 free(p); //释放内存 70 s->count--; //长度减一 71 72 return top; 73 } 74 75 /*返回栈的长度*/ 76 int StackLength(LinkStact s){ 77 return s.count; 78 } 79 80 /*若栈不为空,则返回栈顶元素*/ 81 int GetTop(LinkStact s){ 82 if(s.count == NULL) 83 return 0; 84 else 85 return s.top->data; 86 } 87 88 /*遍历栈*/ 89 void StackTraverse(LinkStact s){ 90 LinkStackPtr p; 91 p=s.top; //指针指向栈顶 92 while(p) //当栈不为空时 93 { 94 printf("%d ",p->data); 95 p =p->next; 96 } 97 } 98 99 int main(){ 100 LinkStact s; 101 printf("进栈10个数据 "); 102 if(InitStack(&s)==1){ 103 for(int i=1;i<=10;i++) 104 PushStack(&s,i); 105 } 106 StackTraverse(s); //遍历栈 107 printf(" "); 108 109 printf("进栈后长度:%d ",StackLength(s)); 110 111 printf("出栈,取栈顶元素,栈顶元素是 :%d",GetTop(s)); 112 printf(" "); 113 114 printf("栈是否为空? 1:0:%d ",StackEmpty(&s)); 115 116 printf("出栈一个元素:%d ",PopStack(&s)); 117 118 StackTraverse(s); 119 120 121 return 0; 122 }
另外附上Java代码
1 package 栈的链式存储间结构; 2 3 public class LinkStack { 4 StackNode top; // 类似于单链表节点 5 int count; // 元素个数 6 7 /** 8 * 栈的初始化 9 */ 10 @SuppressWarnings("unused") 11 public void initStack(LinkStack S) { 12 S = new LinkStack(); 13 if (S == null) { 14 System.out.println("创建栈失败..."); 15 } else 16 S.count = 0; 17 S.top = null; 18 } 19 20 /** 21 * 入栈操作 ,n 表示进栈元素 22 */ 23 public void pushStack(LinkStack S, int n) { 24 StackNode node = new StackNode(); 25 node.data = n; 26 node.next = S.top; // 新节点的next指向栈顶 27 S.top = node; // 栈底指向新节点,类似单链表的插入操作 28 S.count++; 29 } 30 31 /** 32 * 出栈操作 33 */ 34 public void popStack(LinkStack S) { 35 if (S.count != 0) { 36 System.out.println("出栈一个元素:" + S.top.data); 37 S.top = S.top.next; // 栈底指针下移 38 S.count--; 39 } 40 } 41 42 /** 43 * 求栈顶元素 44 */ 45 public int getTop(LinkStack S) { 46 if (S.top != null) { 47 return S.top.data; 48 } else 49 return 0; 50 } 51 52 /** 53 * 遍历栈元素, 54 */ 55 public void traverseStack(LinkStack S) { 56 StackNode p; // 确记:遍历时top指针不能移动,所以只能新建一个对象来指向top的位置 57 p = S.top; 58 while (p != null) { 59 System.out.print(p.data + " "); 60 p = p.next; 61 } 62 } 63 64 /** 65 * 判断栈是否为空 66 * 67 */ 68 public boolean elemptyStack(LinkStack S) { 69 if (S.count == 0) 70 return true; 71 else 72 return false; 73 } 74 75 /** 76 * 清空栈 77 */ 78 public void clearStack(LinkStack S) { 79 while (S.count != 0) { 80 S.top = S.top.next; // 移动到下一位 81 S.count--; 82 } 83 } 84 85 /** 86 * 获取栈长度 87 */ 88 public int getStackLength(LinkStack S) { 89 return S.count; 90 } 91 92 }
1 package 栈的链式存储间结构; 2 3 public class StackNode { 4 int data; 5 StackNode next; 6 }
1 package 栈的链式存储间结构; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 LinkStack stack = new LinkStack(); 7 System.out.println("初始化栈..."); 8 stack.initStack(stack); 9 for (int i = 0; i < 10; i++) 10 stack.pushStack(stack, i); 11 System.out.println("进栈元素:"); 12 stack.traverseStack(stack); 13 System.out.println(""); 14 15 System.out.println("取栈顶元素:"); 16 System.out.println(stack.getTop(stack)); 17 18 System.out.println("栈是否为空:" + stack.elemptyStack(stack)); 19 20 stack.popStack(stack); 21 System.out.println("重新遍历栈元素:"); 22 stack.traverseStack(stack); 23 24 System.out.println("清空栈:"); 25 stack.clearStack(stack); 26 System.out.println("重新遍历栈元素:"); 27 stack.traverseStack(stack); 28 29 System.out.println("获取栈长度:" + stack.getStackLength(stack)); 30 } 31 32 }
完毕 - . -