赞
踩
栈是限定仅在表尾进行插入和删除操作的线性表。
把允许插入和删除操作的一端称为栈顶,另一端称为栈底。栈又称为后进先出的线性表,简称为LIFO结构。(Last In First Out)
和线性表一样,栈也分为顺序栈和链栈,顺序栈尾插尾删的效率都较高,而链栈如果用单链表实现,则尾删效率低,除非使用双向链表。这里我们采用顺序栈的方式实现栈的基本操作。
typedef struct stack
{
STDataType* a;//指向一块数组空间
int top;//记录当前栈顶的位置
int capacity;//记录顺序栈的最大容量
}ST;
void StackInit(ST* ps);//初始化栈
void StackDestroy(ST* ps);//销毁栈
void StackPush(ST* ps, STDataType x);//入栈
void StackPop(ST* ps);//出栈
STDataType StackTop(ST* ps);//返回栈顶元素
bool StackEmpty(ST* ps);//判断栈是否为空
int StackSize(ST* ps);//返回栈中元素的个数
void StackInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType));
ps->top = 0;
ps->capacity = 0;
}
top和capacity初始化为0,其中top初始化为0,top指向栈顶元素的下一个位置,top也可初始化为-1,此时top指向当前的栈顶元素。
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->top = 0;
ps->capacity = 0;
}
将malloc出的数组空间释放掉,top和capacity都置为0
void StackPush(ST* ps,STDataType x) { assert(ps); if (ps->top == ps->capacity)//栈满,考虑扩容 { int newcapacity=ps->capacity == 0 ? 4 : ps->capacity * 2; STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(int)); if (tmp == NULL) { printf("realloc fail\n"); exit(-1); } ps->a = tmp;//重新指向扩容好的空间 ps->capacity = newcapacity;//更新栈的最大容量 } ps->a[ps->top] = x;//因为top指向的是栈顶元素的下一个,所以直接将top位置的值赋值为x ps->top++;//top++,继续指向栈顶元素的下一个 }
这里扩容和顺序表的扩容一样,需要单独考虑第一次扩容的问题,因为第一次capacity的值为0,如果扩大二倍还是0,所以第一次直接赋值为4。
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));//栈不能为空
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));//栈不能为空
return ps->a[ps->top - 1];
}
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
top值若为0,则是空栈,bool值为true,反之则为false
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
因为top指向栈顶元素的下一个位置,所以top的值即为当前栈中元素的个数
void test1() { ST ps; StackInit(&ps); StackPush(&ps,1); StackPush(&ps, 2); StackPush(&ps, 3);//入栈1,2,3 printf("%d\n", StackTop(&ps));//返回栈顶元素 StackPop(&ps);//出栈 StackPush(&ps, 4); StackPush(&ps, 5);//入栈4,5 printf("%d\n", StackSize(&ps));//栈中元素的个数 while (!StackEmpty(&ps))//依次打印栈中的元素 { printf("%d ", StackTop(&ps)); StackPop(&ps); } StackDestroy(&ps);//销毁栈 }
由于对栈的操作都只能在栈顶进行,所以要依次打印栈中的元素,应用循环(只要栈不为空就一直打印),不断返回栈顶元素,并将栈顶元素出栈。
运行结果
队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表(First In First Out),允许插入的一端称为队尾,允许删除的一端称为队头。
typedef struct QNode
{
struct QNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;//头指针和尾指针封装成一个结构体
队列用链式结构实现,因为只能在队头删除,队尾插入,所以应定义两个指针指向单链表,一个实现删除操作,一个实现插入操作。同时将两个指针封装成一个新的结构体,可以避免在接口函数传二级指针。
void QueueInit(Queue* pq);//队列的初始化
void QueueDestroy(Queue* pq);//队列的销毁
void QueuePush(Queue* pq, QDataType x);//入队
void QueuePop(Queue* pq);//出队
QDataType QueueFront(Queue* pq);//返回队头元素
QDataType QueueBack(Queue* pq);//返回队尾元素
bool QueueEmpty(Queue* pq);//判断队列是否为空
int QueueSize(Queue* pq);//返回队列中的元素个数
void QueueInit(Queue* pq)
{
assert(pq);//pq为指向Queue结构体的指针,一定不为空
pq->head = NULL;
pq->tail = NULL;
}
尾指针和头指针都先置空
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)//依次free掉链表的每个结点
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
释放链表中的结点应注意先保存链表下个位置的结点,然后再free,最后头指针和尾指针置NULL
void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); if (newnode == NULL) { printf("malloc fail\n"); exit(-1); } newnode->data = x; newnode->next = NULL; if (pq->head == NULL)//第一次入队,直接将头尾指针指向新结点 { pq->head = pq->tail = newnode; } else//正常尾插 { pq->tail->next = newnode; pq->tail = newnode; } }
这里要单独考虑第一次入队的情况,入队时,尾指针指向新的结点,然后更新尾指针
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));//队列不能为空
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
出队时先提前保存头结点的下一个结点,然后释放头结点,将头指针指向新的头结点
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
头指针指向的即为队头,尾指针指向的即为队尾
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
头指针指向空即为空队列
int QueueSize(Queue* pq)
{
int size = 0;
QNode* cur = pq->head;
while (cur)//遍历整个链表,记录个数
{
size++;
cur = cur->next;
}
return size;
}
void test1() { Queue pq; QueueInit(&pq); QueuePush(&pq, 1); QueuePush(&pq, 2); QueuePush(&pq, 3); QueuePush(&pq, 4); QueuePush(&pq, 5); QueuePush(&pq, 6);//入队1,2,3,4,5,6 printf("%d\n", QueueSize(&pq));//打印队列中元素的个数6 while (!QueueEmpty(&pq)) { printf("%d ", QueueFront(&pq));//依次打印队头元素1,2,3,4,5,6 QueuePop(&pq);//队头元素出队 } printf("\n"); QueueDestroy(&pq); }
测试结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。