0
点赞
收藏
分享

微信扫一扫

数据结构——线性表之 栈 和 队列,详细解析


一、线性表之栈

1、栈的表示和实现

1.1栈的概念及结构


1.2栈的实现表示方法


2、设计栈的功能实现

2.1栈空间通过动态存储数据

typedef int StackDataType;//重定义类型名

typedef struct Stack
{
StackDataType* a;//创建一个指针,用来接收数组首元素地址,数组里面的类型是StackDataType
//用数组来描述栈,因为出栈和入栈都是一个地方
int top;//相当于数组的下标,可以是0或-1,这里我们选择0
int capacity;//数组的容量
}ST;

2.2栈空间的初始化

//初始化结构体,将结构体变量的地址传递过来,是地址传递,这样就能改变实参的内容了
void StackInit(ST* ps)
{
assert(ps);//地址传递,断言好习惯

//动态开辟一个数组的空间,数组的元素类型是StackDataType,将首元素地址赋给指针a
ps->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);
if (ps->a == NULL)//判断是否成功开辟动态空间
{
perror("the mistake is");
}

ps->top = 0; //相当于数组下标,可以初始化0或-1,这里用0
//用0数组下标从0开始,用-1数组下标从-1开始

ps->capacity = 4; //从开辟的动态空间可以看出数组的容量是4
}

2.3栈空间的销毁

//销毁结构体里的内容,地址传递,才能改变实参的内容
void StackDestroy(ST* ps)
{
assert(ps);

free(ps->a);//释放动态开辟的内存
ps->a = NULL;

ps->top = 0; //将结构体里的 相当于数组下标top 和 容量capacity 置为0
ps->capacity = 0;
}

2.4入栈的功能

//入栈,相当于往数组填充数据x
void StackPush(ST* ps,StackDataType x)
{
assert(ps);

if (ps->top == ps->capacity)//申请的动态空间满了,数组的元素和容量相等,需要增容
{
//用relloc函数申请动态空间,创建临时指针变量是怕动态开辟空间失败,增容一般是上一次的2倍
//注意realloc和malloc函数里的参数,realloc有两个,malloc只有一个
StackDataType* tmp = (StackDataType*)realloc(ps->a, sizeof(StackDataType) * ps->capacity * 2);

if (tmp == NULL)//判断是否成功开辟动态空间
{
perror("the mistake is");
}
else //增容成功
{
//printf("增容成功\n");
ps->a = tmp;//将新开辟的动态空间地址赋给指针a
ps->capacity *= 2;
}
}

//不需要增容或增容之后
ps->a[ps->top] = x;//想数组填充数据
ps->top++; //数组下标加1,方便后面下一次入栈;
//同时top从0开始,填充一个数据top就自增一次,所以数据个数和top相等
}

2.5打印栈里数据的功能

//打印栈里的数据
void StackPrint(ST* ps)
{
int i = 0;
for (i = 0; i < ps->top; i++)//因为top初始化的时候是0,存一个数据,top就自增1一次
{
printf("%d ", ps->a[i]);
}
printf("\n");
}

2.6出栈的功能

//出栈,相当于数组最后一个数据除去,一般除数组最后一个元素的方法就是下标减1,效果上相当于除去了
void StackPop(ST* ps)
{
assert(ps);

assert(ps->top > 0);//防止数据里面没有数据,就不需要出栈
//之前入栈的时候,因为top从0开始,填充一个数据top就自增一次,所以数据个数和top相等

ps->top--;//一般除数组最后一个元素的方法就是下标减1,效果上相当于除去了
}

2.7返回栈顶的数据

//返回栈顶的元素,相当于数组的最后一个元素,元素的类型是StackDataType
StackDataType StackTop(ST* ps)
{
assert(ps);

assert(ps->top>0);//防止数据里面没有数据,就不用返回
//因为top0开始,填充一个数据top就自增1一次,删除一个数据top就自减1一次,所以数据个数和top相等

return ps->a[ps->top - 1];//因为下标top是初始化从0开始的,所以数组最后一个元素的下标是top-1
}

2.8返回栈里的数据的个数

//返回栈里的元素的个数,相当于数组里的元素的个数,就是我们前面说的top,个数的类型就是整型int
int StackSize(ST* ps)
{
assert(ps);

return ps->top;//栈里的元素个数和top相等
}

2.9判断栈里是否有数据

//判断栈里是否有元素,用布尔型bool,真就为1,假就为0
bool StackEmpty(ST* ps)
{
assert(ps);

return ps->top == 0;//ps->top==0 为真,则返回值是1;为假,返回值是0
}

3、总代码


4、 代码运行实例


二、线性表之队列

1、栈的表示和实现 

1.1队列的概念和结构

 


 

 1.2队列的实现表示方法


2、设计队列的功能实现

2.1单链表节点的设计

typedef int QDataType;//类型重命名

typedef struct QueueNode//节点用结构体表示
{
struct QueueNode* next;//指向下一个节点
QDataType data;//队列中存储的数据
}QNode;

2.2队列的特殊处理

typedef struct Queue//定义一个结构体,用来存放链表的第一个节点和尾节点
//第一个节点用于对头出(头删),尾节点用于队尾入(尾插)
{
QNode* head;
QNode* tail;
}Queue;

2.3初始化指针head和指针tail

//初始化第一个节点和尾节点
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;//初始化两个节点都用空指针NULL
}

2.4队尾入(尾插) 

// 队尾入(尾插)
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;//单链表节点里的指针要先赋空指针NULL

if (pq->tail == NULL)//判断链表里是否有节点
{
pq->head = pq->tail = newnode;//没有节点,将新节点赋给第一个节点head和尾节点tail
}
else
{
pq->tail->next = newnode;//有节点,直接单链表尾插
pq->tail = newnode;//尾节点向后走一位,方便写一次队尾入(尾插)
}
}

2.5对头出(头删)

// 队头出
void QueuePop(Queue* pq)
{
assert(pq);

assert(pq->head);//防止链表里没有节点,就不需要队头出(头删)

// 1、一个
// 2、多个
if (pq->head->next == NULL)//如果链表里只有一个节点的时候
{
free(pq->head);//直接free点这节点的空间
pq->head = pq->tail = NULL;//将指针head和tail置空
}
else//链表有两个及以上的节点
{
QNode* next = pq->head->next;//先找到第一个节点head的下一个节点next
free(pq->head);//释放第一个节点的空间
pq->head = next;//将节点next作为新的第一个节点,方便下一次的队列出(头删)
}
}

2.6返回对头的数据(链表里的第一个节点的数据)

//访问对头的数据(链表里的第一个节点的数据)
QDataType QueueFront(Queue* pq)
{
assert(pq);

assert(pq->head);//防止链表没有节点,没有节点就访问不了结构体里的数据,不然就会报错

return pq->head->data;//访问对头(第一个节点)里的数据
}

2.7返回队尾的数据(链表里的尾节点的数据)

//访问对尾的数据(链表里的尾节点的数据)
QDataType QueueBack(Queue* pq)
{
assert(pq);

assert(pq->head);//防止链表没有节点,没有节点就访问不了结构体里的数据,不然就会报错

return pq->tail->data;//访问对尾(尾节点)里的数据
}

2.8返回队列(链表)里的数据个数

//队列(链表)里的元素个数
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)//遍历一次,直到链表最后一个节点里的指针(NULL)
{
++size;
cur = cur->next;
}

return size;
}

2.9判断链表里是否有元素

//判断链表里是否有元素 
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;//看第一个节点是否为空指针,
//为空就是没有元素,不为空就是有元素
}

2.10队列空间的销毁

//销毁空间,即返回每个节点开辟的空间
void QueueDestory(Queue* pq)
{
assert(pq);

QNode* cur = pq->head;
while (cur)//遍历一次,直到链表最后一个节点里的指针(NULL)
{
QNode* next = cur->next;
free(cur);//依次释放每个节点的空间
cur = next;
}

pq->head = pq->tail = NULL;//释放完,指针head和 tail置空
}

 

3、总代码


4、代码运行实例

 

 

举报

相关推荐

0 条评论