栈+队列的基本操作实现(严蔚敏版设计思路解读c++)

版权声明:转载请注明出处,谢谢合作 https://blog.csdn.net/qq_40738840/article/details/85271848

大家好,我是集美貌与才华于一身的阿俊呐,咳咳咳…不接受任何反驳,感谢你辣么好看还来关注我,嘿嘿嘿,让我们进入正题叭…biu~ biu~…

这篇博客主要是我学完数据结构(严蔚敏版),想记录下来以后复习用。

  • 从零搭建起栈和队列的操作
  • 顺序动态栈和动态数组的关系(栈也可用链式结构实现,不过不常用)
  • 链式队列和链表的关系(队列也可用顺式结构实现,不过不常用)
  • 数组与链表的优缺点

数据结构设计思路剖析

先聊聊基础的顺序(动态数组)、链式结构(链表)的设计思路,再唠唠如何在已有基础上衍生出比较高级的顺序(动态顺序栈)、链式结构(链队)的设计

动态数组的数据结构

//动态数组的数据结构 
typedef struct
{
	int* elem;//数组首地址
	int length;//数组长度
	int listsize;//数组可用空间
}SqList;
  • 动态数组克服了静态数组无法改变空间大小的缺陷
  • 该数据结构也类似于面向对象思想,将动态数组看做一个对象,其中包含了三个属性,待会儿要实现的功能就是其操作

在动态数组的基础上添加限制,稍作变形,就是顺序动态栈了

顺序动态栈的数据结构

typedef struct
{
	int* base;//栈底
	int* top;//栈顶
	int listsize;//可用空间大小
}SqStack;

看看动态栈是如何由动态数组衍生而来

  • base相当于动态数组的首地址elem
  • top指向最后一个有效元素的下一个位置(特性)
  • top-base = 动态数组的length
  • top = base 时栈空

链表的数据结构

typedef struct	LNode//链表 
{
	int data;//节点中的数据
	struct LNode* next;//指向下一个节点的指针
}LNode,*LinkList;

在链表的数据结构的构成中,可分为两大类:数据项,指针项

  • 数据项可根据需要任意定义,灵活多变
  • 指针项虽然永远只占4位,但也是可指向任意节点

在链表的基础上添加首尾指针,稍作限制,就是队列啦

链式队列的数据结构

typedef struct	LNode//链表 
{
	int data;
	struct LNode* next;
}LNode,*LinkList;
typedef struct
{
	LNode* front;//队头指针
	LNode* rear; //队尾指针
}LinkQueue;

看看队列是如何由链表衍生而来

  • 只需添加指向节点的头尾指针即可,因为链表的特点是只需要知道头指针,就可遍历整个链表;为什么添加尾指针呢?因为队列要求一端进,一端出,所以得充分利用头和尾

功能构造思路

tips

数据结构的定义直接决定了其基本操作及算法实现的难度,所以呀,我们学习数据结构一是为了掌握基本的结构定义,二是体会各种结构是如何构造而来,今后遇到实际问题时方有可能设计出不错的数据结构

操作分为四个部分–增查改删

线性表无论是动态数组/栈还是链表/队列,基本操作均逃不出四座大山–增查改删,让我们来给他们排排序

  • 增加元素永远是老大,因为最开始是0,什么都没有,我们需建立一个表,其余的操作方可进行,建立一个表也就是从空表开始反复增加(插入)元素。若是一个表都不存在,我们拿什么查改删
  • 查找元素是老二,为啥把它排第二,我改删不服。若是把查找排老四,一进行时突然发现,我该改谁呢?同时也发现了这个问题,没有改删的对象可咋办,诶呀呀,你还是快回第二吧。
  • 改删元素位置顺序不太重要,看需要哪个操作多,相较之下,修改元素是比较简单的,找到元素后修改就行,而删除在数组中麻烦,在链表方便

以上的功能排序也是具体实现时的顺序,只要你掌握了动态数组和链表的增查改删

栈功能(仅有增删,无查改)

  • 入栈–增
  • 出栈–删

队列功能(仅有增删,无查改)

  • 入队–增
  • 出队–删

二者由于自身特性限制,比动态数组和链表的功能还少,所以实现起来也较简单,只有两个功能。

一个有意思的偷懒

  • 值得一提的是为啥我们选择在链表的头结点后删除,尾节点插入
    按理说无论是链表的头和尾,均可进行插入删除操作呀。那让我们来唠嗑唠嗑,假设在链表头结点插入,新节点指向头结点后一个元素,头结点指向新节点,插入成功;再看看在尾节点删除,删除得知道尾节点前一个节点,诶嘿,突然发现,单向链表只能往后找,没法回头呀,这时候如果想解决问题,仅有添加一个指向尾节点前一个的指针咯。若是选择在尾部插入,尾节点直接指向新节点就大功告成,头结点删除也很容易。相较之下,后者少用一个指针,更为简单,所以我们采用简单的方法

顺序结构和链式结构的优缺点

  • 顺序结构便于查找,修改,只要寻址即可;而删除,增加需要移动位置,不便于实现
  • 链式结构便于删除,增加,只需改变指针指向,且当节点信息很多时,链式效率极高;而对于查找,修改,必须从头到尾遍历
  • 二者是互补关系,各有所长,应根据实际应用选择合适的结构

完整实现代码

栈实现完整代码

#include<iostream>
using namespace std;
#include<stdlib.h>
#define INIT_SIZE 100
#define INCREMENT 10

//top指向有元素的下一个位置
//top-base = 动态数组的length
//base相当于动态数组的首地址elem 
typedef struct
{
	int* top;
	int* base;
	int listsize;
}SqStack;
void InitStack(SqStack &S)
{
	S.base = (int*)malloc(INIT_SIZE*sizeof(int));
	S.top = S.base;
	S.listsize = INIT_SIZE;
}
//入栈 
void Push(SqStack &S,int e)
{
	if(S.top - S.base >= S.listsize)//动态扩容 
	{
		S.base = (int*)realloc(S.base,(S.listsize+INCREMENT)*sizeof(int));
		S.top = S.base + S.listsize;//更新栈顶 
		S.listsize = S.listsize+INCREMENT;//更新可用空间 
	}
	*S.top = e; 
	S.top++;
}
//空->true;非空->false 
bool IsEmpty(SqStack S)
{
	if(S.top == S.base)return true;
	else return false;
}
//仅删除栈顶,不返回值 
void Pop(SqStack &S)
{
	if(!IsEmpty(S))
	{
		S.top--;//只删除栈顶,不弹出 
	}
	else cout<<"栈空!"<<endl; 
}
//仅返回栈顶值,不删除 
int GetTop(SqStack S)
{
	if(!IsEmpty(S))
	{
		return *(S.top-1);
	}
	else return -11111;//表示空栈 
}

int main()
{
	SqStack S;
	InitStack(S);
	for(int i =0; i <10; i++)
	{
		Push(S,i);
		cout<<GetTop(S);
	}
	cout<<endl;
	for(int i =0; i <10; i++)
	{
		cout<<GetTop(S);
		Pop(S);
	}cout<<GetTop(S);Pop(S);
	return 0;
 } 

队列实现完整代码

#include<iostream>
using namespace std;
#include<stdlib.h>

//队列基本操作
typedef struct QNode
{
	int data;
	struct QNode* next;
}QNode,LNode,*LinkList;

typedef struct
{
	QNode* front;
	QNode* rear;
}LinkQueue;

void InitQueue(LinkQueue &Q)
{
	Q.front = Q.rear = (QNode*)malloc(sizeof(QNode));//头尾均指向头指针 
	Q.front->next = NULL;//尾部赋空 
}
//尾部插入 
void Enqueue(LinkQueue &Q,int data)
{
	QNode* p = (QNode*)malloc(sizeof(QNode));
	p->data = data;
	p->next = NULL;
	
	Q.rear->next = p;
	Q.rear = p;
}
//空->true;非空->false 
bool IsEmpty(LinkQueue Q)
{
	if(Q.front->next)	return false;
	else return true;
}
//头部删除;注意删除的节点为尾节点时,重新将尾节点指向头结点 
void Dequeue(LinkQueue &Q)
{
	if(!IsEmpty(Q))
	{
		Q.front->next = Q.front->next->next;
		if(IsEmpty(Q))	Q.rear = Q.front;//删除尾节点,重新将尾指针指向头 
	}
}
//获取队头元素 
int GetTop(LinkQueue &Q)
{
	if(!IsEmpty(Q))
	{
		return Q.front->next->data;
	}
	else return -111111;
}
int main()
{//模仿栈测试,你写一个队列测试吧
	return 0;
 } 

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/85271848