栈的基础操作的两种实现方法
1. 定义结构体来构建栈
-
链表实现
typedef struct stack{ int element; struct stack *next; }NODE,*Stack;
用指针去连接各个结点
-
数组实现
typedef struct stack{ int Capacity;//可放结点的容量 int topofStack;//数组元素的角标 int *Array;///指向数组首元素地址的指针 }NODE,*Stack;
让数组去存储栈中的各个值,相当于定义了一个Capacity
长度的数组Array
,通过topofStack
来访问数组中的元素
2. 创建栈头createStack
-
链表实现
Stack createStack(){ Stack s=(Stack)malloc(sizeof(NODE)); assert(s); s->next=NULL; return s; }
不需要去为头结点做数据的初始化
-
数组实现
Stack createStack(int maxNumber){ if(maxNumber<5){ printf("too small"); return NULL; } Stack s=(Stack)malloc(sizeof(NODE)); assert(s); s->Array=(int)malloc(sizeof(int)*maxNumber); assert(s->Array); s->Capacity=maxNumber; s->topofStack=-1;//这里将数组角标设为-1,当出现带有数据的结点时数组角标会增加 return s; }
- 数组实现最不方便的一点就是需要提前指定最大容量,不能像链表实现那样随意
- 当然为了避免错误容量的出现,可以设定一个最小容量值与要分配的大小作对比
- 数组实现内部还有一个数组也需要进行内存申请,所以要分配两次
3. 判断是否为空
-
链表实现
int isEmpty(Stack s){ return s->next==NULL; }
直接判断头结点的下一个是否为空即可
-
数组实现
int isEmpty(Stack s){ return s->topofStack==-1; }
如果时头结点那么数组下标将会是
-1
,即空
3. 压栈push
-
链表实现
void push(int n,Stack s){ Stack node; node=(Stack)malloc(sizeof(NODE)); assert(node); node->element=n; node->next=s->next; s->next=node; }
和常规的链表从头部增加结点一样,因为是单指针,原本表头和下一个结点连的那条线要后断
-
数组实现
int isFull(Stack s){ return s->Capacity==s->topofStack+1; }//数组内元素数量和角标的关系 void push(int n,Stack s){ if(isFull(s)){ printf("there is a error!\n"); return; } s->Array[++s->topofStack]=n; //不看括号内的内容,就是正常的给数组元素赋值,而++使数组移向下一个元素 //++结合的优先级低于->,所以是对topofStack进行++的操作 }
正如第二点对于数组缺陷描述的那样,不能随意增加结点,数组实现是有最大长度的
4. 出栈pop
-
链表实现
void pop(Stack s){ if(isEmpty(s)){ printf("there is a false\n"); return; } Stack node=s->next; s->next=node->next; free(node); }
就是常规的从头部删除节点,定义一个临时结点去操作
虽然没有分配堆区内存,但最好还是free
一下 -
数组实现
void pop(Stack s){ if(isEmpty(s)){ printf("there is a error!\n"); return; } s->topofStack--; //和push时一样,--的优先级低于-> }
数组的优势展现,再加下一个结点时只需要覆盖原来的值就好了,所以出栈让其数组元素下标减少就好了,不用像链表那样定义临时节点
5. 查看栈顶元素top
-
链表实现
int top(Stack s){ if(!isEmpty(s)){ return s->next->element; } printf("there is a error\n"); return 0; }
-
数组实现
int top(Stack s){ if(!isEmpty(s)){ return s->Array[s->topofStack]; }//引用链表的下标时不要忘了用s-> printf("there is a error!\n"); return 0; }
6. 销毁栈
- 链表实现
void destroy(Stack s){
Stack pmove=s->next;
while(pmove!=NULL){
free(s);
s=pmove;
pmove=pmove->next;
}
free(s);
}
-
数组实现
void Disposestack(Stack s){ if(s!=NULL){ free(s->Array); free(s); } }
数组实现的直接释放数组就好了,但是别忘了动态分配了两次,所以要释放两次
7. 打印栈printStack
-
链表实现
void printStack(Stack s){ Stack pmove; assert(pmove); pmove=s->next; while(pmove!=NULL){ printf("the element is %d\n",pmove->element); pmove=pmove->next; } free(pmove); }
创建一个新的临时结点去遍历整个链表进行打印
-
数组实现
void printStack(Stack s){ int i; for(i=0;i<s->topofStack+1;i++){ printf("%d ",s->Array[i]); } printf("\n"); }
数据在数组中直接打印就好,但要注意
topofStack
的初值为-1