时间:2019年6月25日20:32:34
前面已经学到了数据结构中的线性表,今天来学习下栈和队列。其实栈和队列都是使用线性表模拟出来的。明白它的原理,就知道栈和队列要如何来实现了。实现很简单,关键是对他们这种存储结构的应用。通过他们的特性我们要知道如何使用这些特性来解决生活中的问题。
1. 栈
1.1 什么是栈
栈就像一个箱子,你从这个箱子的顶部放进去物品,拿得时候只能从顶部中拿;第一次放进去的物品,就会放到这个容器的底部。
比如你要把三本书放进箱子里,全部放到箱子里面后图形是右边这样的。如果想取出第一次放进去的书,那么就需要将它上面的书全部取出来才可以得到,不可能说你破开箱子,直接得到第一次放进去的书。
将书放进箱子里这叫:压栈、入栈、进栈
将书从箱子取出来叫:出栈、弹栈
1.2 栈的特性
从上面的举例,已经知道了只能在栈的顶部进行插入或删除的操作,能进行操作的是栈顶,不能进行操作的是栈底。先进后出
栈也是一种特殊的线性表。我们完全可以通过线性表来模拟栈
我们知道线性表分为顺序存储和链式存储,栈也可以用顺序、链式结构来进行实现
1.3 栈的顺序存储结构操作
在写栈的时候,我们要先明白他的特性先进后出。
- 压栈 在将(1, 2, 3, 4, 5)压入栈中,那么进栈之后他的顺序是(5, 4, 3, 2, 1),通过这一点我们就能想到其实顺序存储栈压栈就是线性表顺序存储的尾插法。线性表的尾部我们记作为栈顶
- 出栈由于栈只能操作一端,既然线性表的尾部是栈顶,所以我们只能从线性表的尾部拿元素,然后输出,刚好是(5, 4, 3, 2, 1)
- 前面已经实现了线性表的顺序存储,直接复用代码
线性表顺序存储.h
typedef void List;
typedef void ListNode;
//线性表的创建
List* List_Create(int size);
//销毁一个线性表
void List_Destroy(List* list);
//将一个线性表中list中所有元素清空,线性表回到创建时的初始状态
void List_Clear(List* list);
//返回一个线性表list中所有元素个数
int List_Length(List* list);
//向一个线性表list的pos位置插入新元素
int List_Insert(List* list, ListNode* node, int pos);
//获取一个线性表list的pos位置的元素
ListNode* List_Get(List* list, int pos);
//删除某一个元素
ListNode* LIst_DeleteNode(List* list, int pos);
//获取线性表的长度
int List_CapCapacity(List* list);
线性表顺序存储.c
#include "List线性表.h"
#include "stdio.h"
#include "malloc.h"
typedef struct PList
{
int lenth;
int size;
int* node;
}PList;
//线性表的创建
List* List_Create(int size)
{
PList* temp = (PList*)malloc(sizeof(PList));
memset(temp, 0, sizeof(PList));
int ret = 0;
if (temp == NULL)
{
ret = -1;
printf("线性表创建失败 temp %d", ret);
return NULL;
}
temp->node = (int *)malloc(sizeof(int *) * size);
if (temp->node == NULL)
{
ret = -2;
printf("节点创建失败 %d", ret);
return NULL;
}
temp->lenth = 0;
temp->size = size;
return temp;
}
//销毁一个线性表
void List_Destroy(List* list)
{
if (list == NULL)
{
printf("list为NULL");
return;
}
PList* temp = (PList*)list;
free(temp->node);
free(temp);
return;
}
//将一个线性表中list中所有元素清空,线性表回到创建时的初始状态
void List_Clear(List* list)
{
if (list == NULL)
{
printf("list为NULL");
return;
}
PList* temp = (PList*)list;
for (int i=0; i<temp->size; i++)
{
temp->node[i] = 0;
}
return;
}
//返回一个线性表list中所有元素个数
int List_Length(List* list)
{
if (list == NULL)
{
printf("list为NULL");
return -1;
}
PList* temp = (PList*)list;
return temp->lenth;
}
//向一个线性表list的pos位置插入新元素
int List_Insert(List* list, ListNode* node, int pos)
{
if (NULL == list || node == NULL)
{
printf("NULL == list || node == NULL err");
return -1;
}
PList* temp = (PList*)list;
if (pos > temp->size)
{
printf("越界 pos err");
return -2;
}
int i = 0;
for (i=temp->lenth; i>pos; i--)
{
temp->node[i] = temp->node[i - 1];
}
temp->node[pos] = (int*)node;
temp->lenth++;
return 0;
}
//获取一个线性表list的pos位置的元素
ListNode* List_Get(List* list, int pos)
{
if (list == NULL)
{
printf("list 为 NULL");
return NULL;
}
PList* temp = (PList*)list;
if (temp->size < pos)
{
printf("越界 temp->node < pos err");
return NULL;
}
return (ListNode *)temp->node[pos - 1];
}
//删除某一个元素
ListNode* LIst_DeleteNode(List* list, int pos)
{
int i = 0;
if (list == NULL || pos < 0)
{
printf("list == null || pos < 0");
return NULL;
}
PList* temp = (PList*)list;
if (pos > temp->size)
{
printf("pos > temp_>size");
return NULL;
}
ListNode* pls = temp->node[pos-1];
//元素前移
for (i=pos-1; i<temp->lenth; i++)
{
temp->node[i] = temp->node[i + 1];
}
temp->node[temp->lenth - 1] = 0;
temp->lenth--;
return pls;
}
//获取线性表的长度
int List_CapCapacity(List* list)
{
if (list == NULL)
{
return -1;
}
PList* temp = (PList*)list;
return temp->size;
}
seqlist_Stack.h
#include "stdio.h"
typedef void SeqStack;
//创建栈
SeqStack* SeqStack_Create(int capacity);
//销毁栈
void SeqStack_Destroy(SeqStack* stack);
//清空栈
void SeqStack_Clear(SeqStack* stack);
//压栈
int SeqStack_Push(SeqStack* stack, void* item);
//出栈
void* SeqStack_Pop(SeqStack* stack);
//获取栈顶元素
void* SeqStack_Top(SeqStack* stack);
//获取栈有效元素个数
int SeqStack_Size(SeqStack* stack);
//获取栈的长度
int SeqStack_Capacity(SeqStack* stack);
seqlist_Stack.c
#include "stdio.h"
#include "seqlist_Stack.h"
#include "List线性表.h"
//创建栈--相当于创建了一个线性表
SeqStack* SeqStack_Create(int capacity)
{
return List_Create(capacity);
}
//销毁栈 -- 销毁线性表
void SeqStack_Destroy(SeqStack* stack)
{
return List_Destroy(stack);
}
//清空栈 -- 清空线性表
void SeqStack_Clear(SeqStack* stack)
{
return List_Clear(stack);
}
//压栈 -- 线性表尾部插入元素
int SeqStack_Push(SeqStack* stack, void* item)
{
return List_Insert(stack, item, List_Length(stack));
}
//出栈 -- 删除线性表尾部元素
void* SeqStack_Pop(SeqStack* stack)
{
return LIst_DeleteNode(stack, List_Length(stack));
}
//获取栈顶元素
void* SeqStack_Top(SeqStack* stack)
{
return List_Get(stack, List_Length(stack));
}
//获取栈有效元素个数
int SeqStack_Size(SeqStack* stack)
{
return List_Length(stack);
}
//获取栈的长度
int SeqStack_Capacity(SeqStack* stack)
{
return List_CapCapacity(stack);
}
1.4 线性表的链式存储模拟栈
LinkList.h
typedef void LinkList;
typedef struct _tag_LinkListNode
{
struct _tag_LinkListNode* next;
}LinkListNode;
//链表的创建
LinkList* LinkList_Create();
//销毁一个线性表
void LinkList_Destroy(LinkList* list);
//将一个线性表中list中所有元素清空,线性表回到创建时的初始状态
void LinkList_Clear(LinkList* list);
//返回一个线性表list中所有元素个数
int LinkList_length(LinkList* list);
//向一个线性表list的pos位置插入新元素
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
//获取一个线性表list的pos位置的元素
LinkListNode* LinkList_Get(LinkList* list, int pos);
//释放
LinkListNode* LinkList_Delete(LinkList* list, int pos);
LinkList.c
#pragma once
#include "线性表链式.h"
#include "stdio.h"
typedef struct _tagLinkList
{
LinkListNode node;
int len;
}TLinkList;
//链表的创建
LinkList* LinkList_Create()
{
TLinkList * temp = NULL;
//创建一个头节点
temp = (TLinkList*)malloc(sizeof(TLinkList));
if (temp == NULL)
{
printf("头节点创建失败 ");
return -1;
}
memset(temp, 0, sizeof(TLinkList));
return temp;
}
//销毁一个线性表
void LinkList_Destroy(LinkList* list)
{
if (list == NULL)
{
return;
}
TLinkList* temp = (TLinkList *)list;
if (temp != NULL)
{
free(temp);
}
return ;
}
//将一个线性表中list中所有元素清空,线性表回到创建时的初始状态
void LinkList_Clear(LinkList* list)
{
if (list == NULL)
{
return;
}
TLinkList* temp = (TLinkList*)list;
temp->len = 0;
temp->node.next = NULL;
return ;
}
//返回一个线性表list中所有元素个数
int LinkList_length(LinkList* list)
{
if (list == NULL)
{
printf("list为NULL");
return -1;
}
TLinkList* temp = (TLinkList*)list;
return temp->len;
}
//向一个线性表list的pos位置插入新元素
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos)
{
int i = 0;
if (list == NULL || node == NULL || pos < 0)
{
printf("list == NULL || node == NULL || pos < 0");
return -1;
}
TLinkList * tlist = (TLinkList *)list;
LinkListNode* curren = &(tlist->node);
for (i=0; i<pos; i++)
{
curren = curren->next;
}
node->next = curren->next;
curren->next = node;
tlist->len++;
return 0;
}
//获取一个线性表list的pos位置的元素
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int ret = 0, i = 0;
LinkListNode* curent = NULL;
TLinkList* tlist = NULL;
if (list == NULL || pos < 0)
{
ret = -1;
printf("list == NULL || pos < 0 %d \n", ret);
return NULL;
}
tlist = (TLinkList*)list;
curent = &(tlist->node);
for (i=0; i<pos; i++)
{
curent = curent->next;
}
return curent->next;
}
//删除
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
if (list == NULL || pos < 0)
{
printf("list == null || pos < 0 error");
return NULL;
}
TLinkList* temp = (TLinkList*)list;
LinkListNode* ret = NULL;
LinkListNode* current = &(temp->node);
int i = 0;
for (i=0; i<pos; i++)
{
current = current->next;
}
ret = current->next;
current->next = ret->next;
temp->len--;
return ret;
}
LinkStack.h
typedef void LinkStack;
//创建栈
LinkStack* LinkStack_Create();
//销毁栈
void LinkStack_Destroy(LinkStack* stack);
//清空栈
void LinkStack_Clear(LinkStack* stack);
//压栈
int LinkStack_Push(LinkStack* stack, void* item);
//出栈
void* LinkStack_Pop(LinkStack* stack);
//获取栈顶元素
void* LinkStack_Top(LinkStack* stack);
//获取栈有效元素个数
int LinkStack_Size(LinkStack* stack);
LinkStack.c
这里的话,需要说明一下,因为我们的线性表的链式存储在编写的时候,我们考虑的是业务节点是带有链表的节点的,但是这里我们直接插入int类型变量,是不带链表节点的,所以我们需要在这里动态的创建链表节点。这个链表节点也要包含我们插入的int类型变量的地址所以这里有两个指针域
typedef struct _tag_StackNode
{
LinkListNode node;
void* item;
}TStackNode;
//创建栈 -- 相当于创建一个链表
LinkStack* LinkStack_Create()
{
return LinkList_Create();
}
//销毁栈 -- 相当于销毁一个链表
void LinkStack_Destroy(LinkStack* stack)
{
LinkStack_Clear(stack);
free(stack);
return ;
}
//清空栈 -- 相当于清空一个链表
void LinkStack_Clear(LinkStack* stack)
{
if (stack == NULL)
{
printf("清空失败 stack == null");
return;
}
while (LinkStack_Size(stack) > 0)
{
LinkStack_Pop(stack);
}
return ;
}
//压栈 -- 相当于从链表的头部插入
int LinkStack_Push(LinkStack* stack, void* item)
{
//int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
int ret = 0;
TStackNode* temp = (TStackNode*)malloc(sizeof(TStackNode));
if (temp == NULL)
{
ret = -1;
printf("节点创建失败!error\n");
return ret;
}
temp->item = item;
ret = LinkList_Insert(stack, (LinkListNode*)temp, 0);
if (ret != 0)
{
free(temp);
}
return ret;
}
//出栈 -- 从链表的头部删除元素
void* LinkStack_Pop(LinkStack* stack)
{
TStackNode * temp = (TStackNode *)LinkList_Delete(stack, 0);
return temp->item;
}
//获取栈顶元素 -- 获取链表的头部元素
void* LinkStack_Top(LinkStack* stack)
{
TStackNode* temp = LinkList_Get(stack, 0);
return temp->item;
}
//获取栈有效元素个数 -- 获取链表的长度
int LinkStack_Size(LinkStack* stack)
{
return LinkList_length(stack);
}
2. 队列
2.1 什么是队列
队列是一种先进先出的线性表,允许插入元素的一端叫队尾,允许删除元素的一端叫队头。
举个例子,你去电影院买票,你看到售票处排着一条常常的队,(其实你可以把他想成一个线性表),你只能站在队列的最后面这叫队尾,在排队的时候,你看到第一个人已经买好票了,他离开了第二个人上去买票了。那么在第一个人离开的时候叫队头。
2.2 队列的特性
通过上面例子你可以发现,我们用线性表来模拟队列的话,只能在队尾插入元素,只能在队头删除元素。这样也就达成了先进先出的条件。当然你去买票的时候不能从中间插队(会被打…)。
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表
2.3 线性表的顺序存储来模拟队列
线性表的顺序存储代码和线性表的链式我就不贴了,上面已经有了。直接上队列的代码
seqqueue.h
typedef void Queue;
//创建队列
Queue* Queue_Create(int capacity);
//销毁队列
void Queue_Destroy(Queue* queue);
//清空队列
void Queue_Clear(Queue* queue);
//进队列
int Queue_Append(Queue* queue, void* item);
//出队列
void* Queue_Retrieve(Queue* queue);
//获取队列头元素
void* Queue_Header(Queue* queue);
//获取队列长度
int Queue_Length(Queue* queue);
//获取队列容量
int Queue_Capacity(Queue* queue);
seqqueue.c
//创建队列 -- 相当有创建顺序存储线性表
Queue* Queue_Create(int capacity)
{
return List_Create(capacity);
}
//销毁队列 -- 相当于销毁顺序存储线性表
void Queue_Destroy(Queue* queue)
{
return List_Destroy(queue);
}
//清空队列
void Queue_Clear(Queue* queue)
{
return List_Clear(queue);
}
//进队列 -- 相当于从尾部插入
int Queue_Append(Queue* queue, void* item)
{
return List_Insert(queue, item, Queue_Length(queue));
}
//出队列 -- 相当于从队列头部删除元素
void* Queue_Retrieve(Queue* queue)
{
return LIst_DeleteNode(queue, 1);
}
//获取队列头元素 -- 相当于从头部获取元素
void* Queue_Header(Queue* queue)
{
return List_Get(queue, 1);
}
//获取队列长度 -- 相当于获取线性表的长度
int Queue_Length(Queue* queue)
{
return List_Length(queue);
}
//获取队列容量 -- 相当于获取线性表容量
int Queue_Capacity(Queue* queue)
{
return List_CapCapacity(queue);
}
2.4 线性表的链式存储来模拟队列
LinkQueue.h
typedef void LinkQueue;
//创建队列
LinkQueue* Queue_Create();
//销毁队列
void Queue_Destroy(LinkQueue* queue);
//清空队列
void Queue_Clear(LinkQueue* queue);
//进队列
int Queue_Append(LinkQueue* queue, void* item);
//出队列
void* Queue_Retrieve(LinkQueue* queue);
//获取队列头元素
void* Queue_Header(LinkQueue* queue);
//获取队列长度
int Queue_Length(LinkQueue* queue);
LinkQueue.c
typedef struct _tag_LinkQueueNode
{
LinkListNode node;
void* item;
}TLinkQueueNode;
//创建队列 -- 相当于创建线性表
LinkQueue* Queue_Create()
{
return LinkList_Create();
}
//销毁队列 -- 相当于销毁元素元素
void Queue_Destroy(LinkQueue* queue)
{
Queue_Clear(queue);
return LinkList_Destroy(queue);
}
//清空队列 -- 相等于清空链表的元素
void Queue_Clear(LinkQueue* queue)
{
while (Queue_Length(queue) > 0)
{
Queue_Retrieve(queue);
}
return LinkList_Clear(queue);
}
//进队列 -- 相当于在链表的尾部添加元素
int Queue_Append(LinkQueue* queue, void* item)
{
TLinkQueueNode* ret = NULL;
ret = (TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));
if (ret == NULL)
{
return -1;
}
memset(ret, 0, sizeof(TLinkQueueNode));
ret->item = item;
return LinkList_Insert(queue, ret, Queue_Length(queue));
}
//出队列 -- 当等于从链表头部删除元素
void* Queue_Retrieve(LinkQueue* queue)
{
TLinkQueueNode* temp = NULL;
void* item = NULL;
temp = (TLinkQueueNode *)LinkList_Delete(queue, 0);
item = temp->item;
if (temp != NULL)
{
free(temp);
}
return item;
}
//获取队列头元素 -- 相等于获取链表的头部元素
void* Queue_Header(LinkQueue* queue)
{
TLinkQueueNode* temp = NULL;
temp = LinkList_Get(queue, 0);
return temp->item;
}
//获取队列长度 -- 相当于获取链表的长度
int Queue_Length(LinkQueue* queue)
{
return LinkList_length(queue);
}