栈与队列的操作

栈与队列

具有的操作:

  • 初始化栈(队列)
  • 判断栈(队列)是否为空
  • 判断栈(队列)是否已满
  • 入栈(队列)
  • 出栈(队列)
  • 遍历栈(队列)

栈满足的特性

  • 先进后出 后进先出

队列满足的特性

  • 先进先出,后进后出

顺序栈(数组形式)

  • 定义数据类型 默认以int类型为主,可以使用模板封装任意类型的栈

    //存int类型数据的顺序栈
    int* pStack;	//指向栈的指针
    int size;		//存储栈中的元素个数
    
  • 栈的操作

    //初始化栈
    void InitStack();
    //入栈
    void push(int data);
    //出栈
    void pop();
    //判断栈是否为空
    bool isEmpty();
    //获取栈顶元素,只能获取栈顶元素
    int getTop();
    //遍历元素
    void _travel();
    
    
  • 初始化栈

    //初始化栈
    void InitStack()
    {
    	pStack = NULL;
    }
    
  • 入栈操作: 分两种方式

    1. 当栈为空的时候,

      void push()
      {
      if (pStack == NULL)
      {
      	//1. 开辟新的空间
      	pNew = (int*)malloc(sizeof(int)*										(size+1));
      	//2. 原来的内存指向新的开辟的内存
      	pStack = pNew;
      	//3. 插入数据
      	pStack[size++] = data;
      }
      
    2. 当栈不为空的时候

      • 即需要在数组的最后添加元素,首先要开辟一块新的内存区域,在新开辟的空间进行数组元素的增加
      
      //栈不为空 操作步骤:
      else
      {
          //1.为后面的开辟新的内存
          int* pNew = (int*)malloc(sizeof(int) * (size + 1));
          //2.将原有的内存数据的元素拷贝到新的内存里
          memcpy(pNew, pStack, sizeof(int) * size);
          //3.释放原有的内存空间
          free(pStack);
          //4.原来的内存指向新的开辟的内存
          pStack = pNew;
          //5.插入数据
          pStack[size++] = data;
      }
      
  • 出栈操作

    • 对于栈,先进的元素后出,后进的元素先出,即首先删除数组末尾的元素,然后依次往前删除

      void pop()
      {
          if (isempty())
          {
              printf("栈为空\n");
              return;
          }
          int* pNew = (int*)malloc(sizeof(int) * (size - 1));
      	memcpy(pNew, pStack, sizeof(int) * (size - 1));
      	free(pStack);
      	pStack = pNew;
      	size--;
      }
      
  • 栈的其他操作

    //判断栈是否为空
    bool isEmpty()
    {
    	return (size == 0);
    }
    //获取栈顶元素,只能获取栈顶元素
    int getTop()
    {
    	return pStack[size-1];
    }
    //遍历元素
    void _travel()
    {
    	printf("size(%d):", size);
    	for (int i = 0; i < size; i++)
    	{
    		printf("%d  ", pStack[i]);
    	}
    	printf("\n");
    }
    
  • 栈的测试

    int main()
    {
    	InitStack();
    	//测试
    	for (int i = 5; i < 15; i++)
    	{
    		push(i);
    		_travel();
    	}
    	while (!isEmpty())
    	{
    		printf("当前栈顶:%d\n", getTop());
    		pop();	//出栈
    	}
    
    	return 0;
    }
    

在这里插入图片描述



顺序队列(数组形式)

  • 队列的操作与栈基本一致 只有出队的时候与出栈不同

  • 队列先进先出 后进后出 先删除数组的第一个元素,在依次往后删除数组元素

  • 出队

    //出队
    int pop()
    {
    	if (isEmpty())
    	{
    		printf("队列为空,出队失败\n");
    		return -1;
    	}
    	/*
    	队列: 先进先出  要删除第一个元素
    	*/
    	//释放第一个元素
    	int ret = pQueue[0];
    	//1. 开辟一个新的内存段
    	int* pNew = (int*)malloc(sizeof(int) * (size - 1));
    	//2. 原有内存段的数据拷贝到新的内存段  要删除第一个 旧的内存区块跳过第一个元素
    	memcpy(pNew, pQueue + 1, sizeof(int) * (size - 1));		
    	//3. 释放原有的内存段
    	free(pQueue);
    	//4. 原有的内存段指向新开辟的内存
    	pQueue = pNew;
    	//5. size减少
    	size--;
    	//6. 返回每次释放的元素
    	return ret;	
    }
    
  • 队列测试

int main()
{
	InitQueue();
	//测试
	for (int i = 5; i < 15; i++)
	{
		push(i);
		_travel();
	}
	int ret = 0;
	while (ret != -1)
	{
		printf("队列顶:%d\n", ret = pop());
	}

	return 0;
}

``在这里插入图片描述



链式栈 (无头节点)

​ 链表的形式存储栈的节点 操作和链表的操作基本一致

  • 这里以结构体类型描述栈的结构

    //栈节点的数据类型
    struct Student
    {
    	char name[50];
    	int age;
    	float score;
    };
    
    typedef struct Student STU;
    #define STU_SIZE sizeof(struct Student)
    
    //存储链式栈的链表
    struct List
    {
    	STU data;
    	struct List* next;
    };
    typedef struct List Node;
    
  • 链式栈的操作

    //创建节点
    Node* CreateNode(STU* data);
    
    //尾插法 入栈
    void push(Node** pHead,STU* data);
    
    //出栈
    Node* pop(Node** pHead);
    
    //遍历栈
    void travel(Node* head);
    
    //打印
    void Printf(STU* p);
    
  • 创建栈节点

    //创建节点
    Node* CreateNode(STU* data)
    {
    	Node* pNew = (Node*)malloc(sizeof(Node));
    	if (pNew == NULL)
    	{
    		printf("创建失败\n");
    		return 0;
    	}
    
    	strcpy(pNew->data.name, data->name);
    	pNew->data.age = data->age;
    	pNew->data.score = data->score;
    	pNew->next = NULL;
    	//返回节点
    	return pNew;
    }
    
  • 入栈 链表的尾插法入栈

    1. 分两种情况,看他是空链表还是非空链表
    
    //尾插法 入栈
    void push(Node** pHead, STU* data)
    {
    	if (pHead == NULL)
    	{
    		return;
    	}
    	//创建新的节点
    	Node* pNew = CreateNode(data);
    	//空链表  新节点要成为当前节点的第一个几点
    	if (*pHead == NULL)
    	{
    		*pHead = pNew;
    	}
    	else
    	{
    		//找到链表的尾部  插入节点
    		Node* pTemp = *pHead;
    		while (pTemp->next)
    		{
    			pTemp = pTemp->next;
    		}
    		//在尾部插入
    		pTemp->next = pNew;
    	}
    }
    
    
  • 出栈

    1. 删除链表的最后一个节点,依次往前删除
    //出栈  删除末尾节点
    Node* pop(Node** pHead)
    {
    	if (pHead == NULL || *pHead == NULL)
    	{
    		return NULL;
    	}
    	//找到链表的最后一个节点
    	Node* pTail = *pHead;
    	while (pTail->next)
    	{
    		pTail = pTail->next;
    	}
    	//1. 如果链表只有一个节点,第一个就等于末尾节点
    	if (pTail == *pHead)
    	{
    		*pHead = NULL;
    	}
    	//2. 如果有多个节点 找到最后一个的前一个并且删除最后一个
    	else
    	{
    		Node* pPreTail = *pHead;
    		while (pPreTail->next != pTail)
    		{
    			pPreTail = pPreTail->next;
    		}
    		//最后一个节点的前一个节点next置空  实现删除最后一个
    		pPreTail->next = NULL;
    	}
    	return pTail;
    }
    
    
  • 遍历及打印

    //遍历栈
    void travel(Node* pHead)
    {
    	if (pHead == NULL)
    	{
    		printf("栈为空\n");
    		return;
    	}
    	Node* pTemp = pHead;
    	while (pTemp)
    	{
    		//传入地址
    		Printf(&(pTemp->data));
    		pTemp = pTemp->next;
    	}
    }
    
    //打印
    void Printf(STU* p)
    {
    	printf("姓名:%s 年龄:%d 成绩:%.2f\n",
    		p->name, p->age, p->score);
    }
    
  • 链式栈测试

    int main()
    {
    	STU info[5] = {
    		{"关羽",55,55.55},
    		{"张飞",44,44.44},
    		{"赵云",33,33.33},
    		{"马超",22,22.22},
    		{"黄忠",11,11.11},
    	};
    
    	Node* pHead = NULL;
    
    	//入栈
    	for (int i = 0; i < 5; i++)
    	{
    		push(&pHead, &info[i]);
    	}
    	travel(pHead);
    	printf("\n\n");
    	//出栈
    	Node* pStackTemp = NULL;
    	while (1)
    	{
    		pStackTemp = pop(&pHead);
    		if (pStackTemp == NULL)
    		{
    			printf("出栈失败\n");
    			break;
    		}
    		Printf(&pStackTemp->data);
    		//释放内存
    		free(pStackTemp);
    		printf("\n\n");
    	}
    	return 0;
    }
    

    在这里插入图片描述



链式队列(无头节点)

  • 操作和链式栈基本一致,除了出栈和出队
  • 出队: 先进先出 后进后出 先删除首元节点,再依次往后删除节点
//出队  删除头节点  
Node* pop(Node** pHead)
{
	if (pHead == NULL || *pHead == NULL)
	{
		printf("出队失败\n");
		return NULL;
	}
	Node* pTemp = *pHead;
	//只有一个节点
	if (( * pHead)->next == NULL)
	{
		*pHead = NULL;
	}
	else
	{
		//有多个节点,则跳过第一个
		*pHead = ( * pHead)->next;
	}
	return pTemp;
}

  • 链式队列测试

    • 代码一致,只需要把出队和出栈的代码改一下

    在这里插入图片描述

  • 源码下载

数组链表栈与队列以及C++模板栈与队列

posted @ 2022-08-01 14:20  hugeYlh  阅读(9)  评论(0编辑  收藏  举报  来源