【数据结构】--- 探索栈和队列的奥秘

04-10 1033阅读

【数据结构】--- 探索栈和队列的奥秘

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა

💡个人主页:9ilk

💡专栏:数据结构之旅


上回我们学习了顺序表和链表,今天博主来讲解两个新的数据结构 — 栈和队列 , 请放心食用

文章目录

  • 🏠 栈
    • 📒 何为栈
      • 👿 栈后进先出是相对的
      • 📒 栈的实现
      • 🏠 队列
        • 📒 何为队列
        • 📒 队列的实现

          🏠 栈

          【数据结构】--- 探索栈和队列的奥秘

          对于这么坨书,我们要拿到最下面的书是不是要最后才能拿到;而对于最上面的书它是最晚放上去的却能最先拿到,这样的一个场景就跟我们接下来要介绍的栈类似 — Last in First out(后进先出)

          📒 何为栈

          【数据结构】--- 探索栈和队列的奥秘

          栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

          压栈:栈数据的插入操作叫做压栈/入栈/进栈,入数据在栈顶。

          出栈:栈数据的删除操作叫做出栈,出数据也在栈顶。

          👿 栈后进先出是相对的

          【数据结构】--- 探索栈和队列的奥秘

          由图中我们可知,栈的后进先出是对于同时在栈里的数据而言的

          📒 栈的实现

          通过前面的分析我们知道,我们需要一个栈顶来表示数据,这跟我们链表的头结点有点相似,但是对于单链表来说实现栈,尾部插入数据并不方便,因此我们选择数组实现栈

          【数据结构】--- 探索栈和队列的奥秘

          • 动态栈
            typedef int Datatype;
            typedef struct Stack
            {
            	Datatype* arr;
            	int top;
            	int capacity;
            }ST;
            
            • 栈的初始化与销毁
              //初始化
              void StackInit(ST* ps)
              {
              	assert(ps);
              	ps->arr = NULL;
              	ps->capacity = ps->top = 0;
              }
              

              关于top的初始化:1.top表示栈顶元素的下一个位置时,让top初始化为0,插入数据时先top后++ ;2.top表示栈顶元素 时,top初始化为-1,此时先++后再用top

              // 销毁栈 
              void StackDestroy(ST* ps)
              {
              	assert(ps);
              	free(ps->arr);
              	ps->arr = NULL;
              	ps->capacity = ps->top = 0;
              }
              
              • 栈的插入数据和删除数据

                这里有了前面顺序表的基础就很简单了,不过要注意压栈和出栈都是在栈顶

                //入栈
                void StackPush(ST* ps, Datatype data)
                {
                	assert(ps);
                	if (ps->capacity == ps->top)
                	{//扩容
                		int newcapacity = 0;
                		newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
                		Datatype* temp = (Datatype*)malloc(newcapacity * sizeof(Datatype));
                		if (temp == NULL)
                		{
                			perror("malloc failed");
                			return;
                		}
                		ps->arr = temp;
                		ps->capacity = newcapacity;
                	}
                	//入栈
                	ps->arr[ps->top++] = data;
                }
                //出栈
                void StackPop(ST* ps)
                {
                	assert(ps);
                	//栈不能为空
                	assert(ps->top != 0);
                	ps->top--;
                }
                
                • 获取栈顶元素
                  // 获取栈顶元素 
                  Datatype StackTop(ST* ps)
                  {
                  	assert(ps);
                  	//栈不能为空
                  	assert(ps->top != 0);
                  	return ps->arr[ps->top - 1];
                  }
                  
                  • 判断是否为空
                    // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
                    int StackEmpty(ST* ps)
                    {
                    	assert(ps);
                    	return ps->top == 0 ? 1 : 0;
                    }
                    
                    • 获取栈中有效数据个数
                      // 获取栈中有效元素个数 
                      int StackSize(ST* ps)
                      {
                      	assert(ps);
                      	return ps->top;
                      }
                      

                      🏠 队列

                      栈是后进先出,那有我们的先进先出(First in First out)吗 ? 当然有,跟现实中我们排队买票一样,这样数据结构叫做队列

                      📒 何为队列

                      【数据结构】--- 探索栈和队列的奥秘

                      队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

                      📒 队列的实现

                      由于我们是先进先出,出在队头出,进在队尾进,所以我们需要两个“指针”front 和 rear 来标识位置有效率些。

                      那用数组来实现好还是链表呢?

                      【数据结构】--- 探索栈和队列的奥秘

                      用数组的话不好出数据,所以我们这里推荐用链表实现;同时我们可以将front和rear封装进一个结构体这样比较省事

                      • 队列结构
                        typedef int Datatype;
                        typedef struct QNode
                        {
                        	Datatype data;
                        	struct QNode* next;
                        }QNode;
                        typedef struct Quque
                        {
                        	QNode* head;
                        	QNode* tail;
                        	int size;
                        }Quque;
                        

                        注:我们可以定义一个size表示数据个数,弥补链表需要循环遍历确定数据个数的缺陷

                        • 队列的初始化和销毁
                          //队列的初始化和摧毁
                          void QuqueInit(Quque* pq)
                          {
                          	assert(pq);
                          	pq->size = 0;
                          	pq->head = pq->tail = NULL;
                          }
                          void QuqueDestroy(Quque* pq)
                          {
                          	assert(pq);
                          	QNode* cur = pq->head;
                          	while (cur)
                          	{
                          		QNode* next = cur->next;
                          		free(cur);
                          		cur = next;
                          	}
                          	pq->head = pq->tail = NULL;
                          	pq->size = 0;
                          }
                          
                          • 入队和出队

                            出队就是链表的头删 入队就是尾插

                            //队列的入队列和出队列
                            void QuquePop(Quque* pq)
                            {
                            	assert(pq);
                            	assert(pq->head != NULL);//对嘞不能为空
                            	//0个结点
                            	//1个结点
                            	if (pq->head->next == NULL)
                            	{
                            		free(pq->head);
                            		pq->head = pq->tail = NULL;
                            	}
                            	else
                            	{
                            		QNode* next = pq->head->next;
                            		free(pq->head);
                            		pq->head = next;
                            	}
                            	pq->size--;
                            }
                            void QuquePush(Quque* pq, Datatype x)
                            {
                            	assert(pq);
                            	//申请新结点
                            	QNode* newnode = (QNode*)malloc(sizeof(QNode));
                            	if (newnode == NULL)
                            	{
                            		perror("malloc failed");
                            		return;
                            	}
                            	newnode->data = x;
                            	newnode->next = NULL;
                            	if (pq->head == NULL)
                            	{//0个结点
                            		pq->head = pq->tail = newnode;
                            	}
                            	else
                            	{
                            		pq->tail->next = newnode;
                            		pq->tail = newnode;
                            	}
                            	pq->size++;
                            }
                            
                            • 获取头元素和尾元素
                              //队列的头元素和尾巴元素
                              Datatype QuqueFront(Quque* pq)
                              {
                              	assert(pq);
                              	assert(pq->head != NULL);
                              	return pq->head->data;//设置两个指针进结构体的好处
                              }
                              Datatype QuqueBack(Quque* pq)
                              {
                              	assert(pq);
                              	assert(pq->head != NULL);
                              	return pq->tail->data;//设置两个指针进结构体的好处
                              }
                              
                              • 队列是否为空
                                //队列是否为空
                                bool QuqueEmpty(Quque* pq)
                                {
                                	assert(pq);
                                	if (pq->size == 0)
                                	{
                                		return true;
                                	}
                                	else
                                	{
                                		return false;
                                	}
                                }
                                
                                • 队列有效数据个数
                                  //队列数据个数
                                  int QuqueSize(Quque* pq)
                                  {
                                  	assert(pq);
                                  	return pq->size;
                                  }
                                  

                                  本次分享到这就结束咯,下次我们将讲解链表,栈和队列的OJ题,敬请期待 ~

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]