#include <stdio.h>
#include <stdlib.h>
//这里是用数组实现堆栈的两种方式,第一种是单方向的,第二种是双方向的。
#define MaxSize 100
struct SNode
{
int data[MaxSize];
int top;
};
typedef struct SNode *Stack;
//用一个数组实现两个堆栈
struct DNode
{
int data[MaxSize];
int top1;
int top2;
};
typedef struct DNode* DStack;
//入栈
void Push(Stack PtrS, int item)
{
if (PtrS->top == MaxSize - 1)
{
printf("Error:Stack Full");
return;
}
else
{
PtrS->top++; //栈指针向上移动
PtrS->data[PtrS->top] = item; //站指针指向地址存放新的数据
return;
}
}
//出栈
int Pop(Stack PtrS)
{
if (PtrS->top == -1)
{
printf("Error:Stark is Empty");
return -1;//返回-1说明为空
}
return (PtrS->data[PtrS->top--]);
}
//从数组的两端向堆栈中存放数据
void DPush(DStack PtrS, int item, int Tag)//Tag用于判断是堆栈1还是堆栈2
{
if (PtrS->top2 - PtrS->top1 == 1)
{
printf("Error:Full of the Stark");
}
else
{
if (Tag == 1)
{
PtrS->top1++;
PtrS->data[PtrS->top1] = item;
}
else
{
PtrS->top2--;
PtrS->data[PtrS->top2] = item;
}
}
}
//从两个堆栈的指针处向两端释放一个数据
int DPop(DStack PtrS, int Tag)
{
if (Tag == 1)
if (PtrS->top1 == -1)
{
printf("Error:Stark 1 is Empty");
return -1;
}
else return(PtrS->data[PtrS->top1--]);
else
if (PtrS->top2 == MaxSize)
{
printf("Error:Stark 2 is Empty");
return -1;
}
else
{
return(PtrS->data[PtrS->top2++]);
}
}
int main()
{
Stack new_stack = (Stack)malloc(sizeof(struct SNode));
new_stack->top = -1;
Push(new_stack,5);
Push(new_stack,10);
printf("%d \n", Pop(new_stack));
printf("%d \n", Pop(new_stack));
//结果应该先出5,再出10
DStack new_dstack = (DStack)malloc(sizeof(struct DNode));
new_dstack->top1 = -1;
new_dstack->top2 = MaxSize;
DPush(new_dstack, 8, 1);
DPush(new_dstack, 9, 1);
DPush(new_dstack, 12, 2);
DPush(new_dstack, 13, 2);
printf("%d ", DPop(new_dstack, 1));
printf("%d ", DPop(new_dstack, 1));
printf("%d ", DPop(new_dstack, 2));
printf("%d ", DPop(new_dstack, 2));
//输出应该为9 8 13 12
return 0;
}
第二种是通过链表实现堆栈的操作。
#include <stdio.h>
#include <stdlib.h>
/*
用链表实现堆栈的时候,实质操作的就是头节点后面的那个节点。
Push就是插入,将一个新的内存空间插入在头结点之后
Pop就是删除,将头后面的节点删除
我们可以形象的理解成,数组的堆栈的底部在下面,成 u 型。入栈数据从上插入,出栈指针下移,从上往下数据出栈。
链表实现堆栈的底部在上面,成 n 型。指针不动,入栈数据从下方插入,出栈从下方拿出。
*/
struct SNode
{
int data;
struct SNode *next;
};
typedef struct SNode* PtrS;
typedef struct SNode Stack;
PtrS CreateStack()
{
PtrS new_stack = (PtrS)malloc(sizeof(Stack));
new_stack->next = NULL;
return new_stack;
}
int IsEmpty(PtrS S)
{
return (S->next == NULL);
}
void Push(int item, PtrS S)
{
PtrS TmpCell;
TmpCell = (PtrS)malloc(sizeof(Stack));
TmpCell->data = item;
TmpCell->next = S->next;
S->next = TmpCell;
}
int Pop(PtrS S)
{
PtrS FirstCell;//用于删除第一个有内容的节点
int TopData;
if (IsEmpty(S))
{
printf("Error:Stack is empty");
return NULL;
}
else
{
FirstCell = S->next;
S->next = FirstCell->next;
TopData = FirstCell->data;
free(FirstCell);
return TopData;
}
}
最后一个是队列,在这个例子里,给出了用数组所构成的循环队列和用链表构建的队列
#include <stdio.h>
#include <stdlib.h>
////用数组实现循环队列
//#define MAXSIZE 100
//
//struct QNode
//{
// int data[MAXSIZE];
// int front;//指向头一个元素的再前一个,删除时后移
// int rear;//添加的时候rear++
//};
//typedef struct QNode* Queue;
///*
//两种方法解决rear == front时判断是空还是满。
//1.使用额外的标记:size或者tag
//2.只使用MAXSIZE-1的方案
//*/
//void AddQ(Queue PtrQ, int item)
//{
// if ((PtrQ->rear + 1) % MAXSIZE == PtrQ->front)
// {
// printf("Error:Queue is Full");
// return;
// }
// else
// {
// PtrQ->rear = (PtrQ->rear + 1) % MAXSIZE;//注意rear的初始值为-1,front也为-1.对maxsize求余正好得到0到maxsize-1。
// PtrQ->data[PtrQ->rear] = item;
// }
//}
//
//int ExitQ(Queue PtrQ)
//{
// if (PtrQ->front == PtrQ->rear)
// {
// printf("Error:The Queue is Empty");
// return -1;
// }
// else
// {
// PtrQ->front = (PtrQ->front + 1) % MAXSIZE;//不能只用PtrQ->front++,因为要考虑到循环队列的循环性质。
// return PtrQ->data[PtrQ->front];
// }
//}
//用单链表实现队列,问题:front和rear应该分别指向链表的哪一头
//链表头做插入,front,链表尾做删除,rear。如果链表尾做front,会导致删除后不知道前一个在哪。(可以通过双向链表解决)
struct Node
{
int data;
struct Node *next;
};
typedef struct Node* PNode;
struct QNode //链队列结构
{
PNode rear;//指向队尾的节点·
PNode front;//指向队首的节点
};
typedef struct QNode *Queue;
Queue PtrQ;
//不带头节点的链式队列的出队操作
int ExitQ()
{
PNode FrontCell;
int item;
if (PtrQ->front == NULL)
{
printf("Error:The Queue is Empty");
return -1;
}
FrontCell = PtrQ->front;
if (PtrQ->front == PtrQ->rear)//说明只有一个元素
PtrQ->front = PtrQ->rear = NULL;//删除后都指向空
else PtrQ->front = PtrQ->front->next;//将front向后移动一个节点
item = FrontCell->data;//将数据取出
free(FrontCell);//将原来的front节点的内存空间释放
return item;//返回数据
}
//不带头节点的链式队列的入队操作
void AddQ(int item)
{
//typedef struct Node* PNode;
PNode New_Node = (PNode)malloc(sizeof(struct Node));//创建一个节点,准备插入至队列尾
New_Node->next = NULL;
//Queue PtrQ;之前申明了,是一个全局变量,表示整个队列。
//如果没申明,那在函数入口参数应该有一个:Queue PtrQ,用来说明插入到什么队列中,
PtrQ->rear->next = New_Node;//添加至队列的尾巴
PtrQ->rear = New_Node;//指向新的队尾,也可以用PtrQ->rear = PtrQ->rear->next;
New_Node->data = item;
}