初阶数据结构—栈和队列

第一章:栈

1.1栈的概念及结构

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

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

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

1.2 栈的实现 

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

栈头文件各函数声明
#pragma once
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int STDataType;
typedef struct Stack//数组栈
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}ST;

void STInit(ST* pst);//初始化栈
void STDestroy(ST* pst);//销毁栈
void STPush(ST* pst, STDataType x);//入栈
void STPop(ST* pst);//出栈
STDataType STTop(ST* pst);//获取栈顶元素
bool STEmpty(ST* pst);//栈是否为空
int STSize(ST* pst);//栈中有效元素个数

栈各函数实现
初始化栈
void STInit(ST* pst)//初始化栈
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0; //该初始化方式,栈顶指向【栈顶元素的后面】。先插入,再++
	//pst->top = -1;//该初始化方式,栈顶指向【栈顶元素】。先++,再插入
	pst->capacity = 0;
}
栈是否为空
bool STEmpty(ST* pst)//栈是否为空
{
	assert(pst);
	return pst->top == 0;//为空返回true;不为空返回false
}
入栈
void STPush(ST* pst, STDataType x)//入栈
{
	assert(pst);
	if (pst->top == pst->capacity)//检查容量(如果栈顶等于容量)
	{
		int newCapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;//栈容量为0就开辟4个单位,否则开辟原容量2倍
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newCapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

出栈
void STPop(ST* pst)//出栈
{
	assert(pst);
	assert(!STEmpty(pst));
	pst->top--;
}

获取栈顶元素
STDataType STTop(ST* pst)//获取栈顶元素
{
	assert(pst);
	assert(!STEmpty(pst));
	return pst->a[pst->top - 1];
}

栈中有效元素个数
int STSize(ST* pst)//栈中有效元素个数
{
	assert(pst);
	return pst->top;
}

销毁栈
void STDestroy(ST* pst)//销毁栈
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}

栈的测试
void TestStack1()
{
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	printf("%d ", STTop(&st));
	STPop(&st);
	STPush(&st, 3);
	STPush(&st, 4);
	while (!STEmpty(&st))
	{
		printf("%d ", STTop(&st));
		STPop(&st);
	}

	STDestroy(&st);
}

int main()
{
    TestStack1();//2 4 3 1
    return 0;
}

第二章:队列

2.1 队列的概念及结构

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

2.2 队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

队里头文件各函数声明
#pragma once

#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int QDataType;
typedef struct QueueNode //队列节点
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue //储存队列节点头尾指针及节点个数的结构体
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);//队列初始化
void QueueDestroy(Queue* pq);//队列释放
void QueuePush(Queue* pq, QDataType x);//队列插入
void QueuePop(Queue* pq);//队列删除
QDataType QueueFront(Queue* pq);//取队头数据
QDataType QueueBack(Queue* pq);//取队尾数据
int QueueSize(Queue* pq);//队列元素个数
bool QueueEmpty(Queue* pq);//队列是否为空

队列各函数实现
初始化队列
void QueueInit(Queue* pq)//初始化队列
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

队列是否为空

队列的插入、删除、获取队头队尾数据需要判断是否为空

//队列的插入、删除、获取队头队尾数据需要判断是否为空
bool QueueEmpty(Queue* pq)//队列是否为空
{
	assert(pq);
	return pq->phead == NULL && pq->ptail == NULL;
}

队尾入队列
void QueuePush(Queue* pq, QDataType x)//队列插入
{
	assert(pq);
	//创建队列节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc newnode fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;

	//插入
	if (QueueEmpty(pq) == true)
		pq->phead = pq->ptail = newnode;
	else //非空队列
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

队头出队列
void QueuePop(Queue* pq)//队列删除
{
	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->phead->next == NULL) //1.一个节点
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else //2.多个节点
	{    //头删
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}

获取队列头部元素
QDataType QueueFront(Queue* pq)//取队头数据
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->phead->data;
}

获取队列队尾元素
QDataType QueueBack(Queue* pq)//取队尾数据
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->ptail->data;
}

获取队列中有效元素个数
int QueueSize(Queue* pq)//队列元素个数
{
	assert(pq);
	return pq->size;
}

释放队列
void QueueDestroy(Queue* pq)//释放队列
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;
		free(del);
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

队列测试
#include "Queue.h"
#include <stdio.h>

void TestQueue()
{
	Queue q;
	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	printf("%d ", QueueFront(&q));
	QueuePop(&q);

	QueuePush(&q, 3);
	QueuePush(&q, 4);
	printf("Size:%d\n", QueueSize(&q));

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}

	QueueDestroy(&q);
}

int main()
{
	TestQueue();
	return 0;
}

第三章:栈和队列面试题

1. 括号匹配问题

20. 有效的括号 - 力扣(LeetCode)

给定一个只包括 '(' ,')' ,'{' ,'}' ,'[' ,']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

注意:此题需要用到上面栈实现的各函数

//1. 创建并初始化栈
//2. 数组指针遇到左括号入栈
//3. 数组指针遇到右括号份2种情况:
//    a. 栈为空,返回假。(说明之前没有遇到左括号)
//    b. 栈不为空,获取栈顶元素与数组指针指向元素比较是否匹配。(注意匹配条件,找为假的情况)
//重复上述步骤直到遍历完数组。
//4.最后判断栈是否为空。空为真,非空为假。
bool isValid(char* s) {
    ST st;// 创建栈       
    STInit(&st); // 初始化栈

    // 1.左括号入栈
    // 2.出栈元素与右括号匹配
    while (*s) { // 遍历数组                                
        if (*s == '(' || *s == '[' || *s == '{') // 左括号入栈
            STPush(&st, *s);
        else { // 出栈元素与右括号匹配                    
            // 在出栈之前要判断栈是否为空,如果为空,说明没有左括号,直接返回假
            if (STEmpty(&st)) {
                STDestroy(&st);
                return false;
            }

            char top = STTop(&st); // 获取栈顶元素
            STPop(&st); // 将栈顶元素出栈
            //if ((*s == ')' && top == '(') || (*s == ']' && top == '[') || (*s == '}' && top == '{'))
            //这里不能用上方条件判断正确后直接返回true,因为最后一个元素为左括号时也满足,但不正确 
            //下方如果栈顶元素与数组指针指向元素不匹配返回假
            if ((*s == ')' && top != '(') || (*s == ']' && top != '[') || (*s == '}' && top != '{')) {
                STDestroy(&st);
                return false;
            }
        }
        s++;
    }
    //这里判断栈里是否还有元素,
    // 如果有,说明有一个单独的左括号,不匹配
    // 如果没有,说明都匹配完成
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}

2. 用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。(此题需要用到上方队列实现的各函数)

// 往不为空的队列插入数据,当需要弹出时,将n-1个数据插入到另外一个队列,此时需要弹出的数据就在该队列最前端。反之亦然
typedef struct {
    // Queue为储存队列节点头尾指针及节点个数的结构体
    Queue q1, q2;//创建2个用于维护两个队列

    // Queue *q1, *q2;
    //这样创建不好,因为未初始化,所以是野指针,当下方调用QueueInit函数初始化时,就会造成对野指针的解引用
    //除非使用malloc开辟Queue结构体的空间。而且后续使用完还需要释放。
    // 不如创建2个Queue结构体封装到MyStack结构体中,直接malloc开辟MyStack需要的空间
} MyStack;

// 两个队列在操作完数据后,一定是某一个为空,或者两个都为空
MyStack* myStackCreate() {
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    if (obj == NULL) {
        perror("malloc MyStack* obj fail");
        return NULL;
    }
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);

    return obj;
}

void myStackPush(MyStack* obj, int x) {
    if (!QueueEmpty(&obj->q1)) //当q1不为空时,往q1入数据
        QueuePush(&obj->q1, x);
    else
        QueuePush(&obj->q2, x); //只要q1有数据,就可以向q2插入数据
}

int myStackPop(MyStack* obj) { //栈的pop是后进先出
    // 弹出数据时就是在两个队列相互导数据,所以要判断哪个队列为空
    // 1.创建名为空和非空的变量。假设q1为空,q2不为空,如果假设错误,互换。
    // 2.将非空队列的数据导入空队列。非空队列数据剩余1时,该数据就是要弹出的数据

    //第一步
    Queue* pEmptyQ = &obj->q1;
    Queue* pNonEmptyQ = &obj->q2;
    if (!QueueEmpty(&obj->q1)) {
        pEmptyQ = &obj->q2;
        pNonEmptyQ = &obj->q1;
    }

    // 第二步
    while (QueueSize(pNonEmptyQ) > 1) { //非空队列数据还剩1个时就是要弹出的数据
        QueuePush(pEmptyQ, QueueFront(pNonEmptyQ));//非空队列取队头数据插入到空队列
        QueuePop(pNonEmptyQ);//弹出非空队列数据
    }
    int top = QueueFront(pNonEmptyQ);//此时非空队列还剩1个数据,取非空队列队头数据
    QueuePop(pNonEmptyQ);//再弹出非空队列的数据
    return top;
}

int myStackTop(MyStack* obj) {
    if (!QueueEmpty(&obj->q1)) //如果q1队列不为空,那么返回q1队列的队尾数据
        return QueueBack(&obj->q1);
    else
        return QueueBack(&obj->q2);//如果q2队列不为空,那么返回q2队列的队尾数据
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);//q1或q2队列是否为空都需要释放。为空只是没有数据,但队列已经申请了空间
    QueueDestroy(&obj->q2);
    free(obj);
    //不能直接释放obj,因为obj里面是两个维护【队列头尾指针和节点个数】的结构体。
    // 释放obj只是释放了这两个结构体的空间,但是队列的节点还未释放
}

3. 用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty)。(此题需要用到上方实现的各函数)

typedef struct {
	ST pushst;
	ST popst;
} MyQueue;


MyQueue* myQueueCreate() {
	MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
	if (obj == NULL) {
		perror("malloc MyQueue* obj fail");
		return NULL;
	}
	STInit(&obj->pushst);
	STInit(&obj->popst);
	return obj;
}

void myQueuePush(MyQueue* obj, int x) {
	STPush(&obj->pushst, x);
}

int myQueuePeek(MyQueue* obj) {
	if (STEmpty(&obj->popst)) {
		while (!STEmpty(&obj->pushst)) {
			STPush(&obj->popst, STTop(&obj->pushst));
			STPop(&obj->pushst);
		}
	}
	return STTop(&obj->popst);
}

int myQueuePop(MyQueue* obj) {
	int front = myQueuePeek(obj);
	STPop(&obj->popst);
	return front;
}

bool myQueueEmpty(MyQueue* obj) {
	return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}

void myQueueFree(MyQueue* obj) {
	STDestroy(&obj->pushst);
	STDestroy(&obj->popst);
	free(obj);
}

4. 设计循环队列

622. 设计循环队列 - 力扣(LeetCode)

思路:
用数组队列,front指向头元素,rear指向尾元素的后面。
假设有k个数据,那么开辟k+1个空间,因为rear需要指向尾元素后面
注意:rear不能指向尾元素,否则只有一个元素时,或满元素时,front和rear都指向同一位置,无法判断满还是空

typedef struct {
    int front; // 队列头下标
    int rear;  // 队列尾下标
    int k;     // 元素个数(但开辟空间要比数据多一个)
    int* a;    // 数组
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj) { //队列是否为空
    return obj->front == obj->rear;//头尾下标相等即为空
}

bool myCircularQueueIsFull(MyCircularQueue* obj) { //队列是否满
    return (obj->rear + 1) % (obj->k + 1) == obj->front;
    // 因为rear指向最后元素后面,又因队列空间比满元素多1。
    // 即rear指向的是队列最后一个空间,所以rear+1就和front指向同一位置。
    // 因为是循环队列,所以rear+1要%队列空间个数
}

MyCircularQueue* myCircularQueueCreate(int k) { //创建队列
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//开辟维护队列信息结构体的空间
    if (obj == NULL) {
        perror("malloc MyCircularQueue* obj fail");
        return NULL;
    }
    obj->a = (int*)malloc(sizeof(int) * (k + 1));//开辟队列
    obj->front = obj->rear = 0;//头尾下标指向同一位置(也就是空队列)
    obj->k = k;//队列元素个数
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { //插入数据
    if (myCircularQueueIsFull(obj))//队列满返回false
        return false;

    obj->a[obj->rear++] = value;//在rear位置处插入数据,rear++
    //因为循环队列,rear可能回到数组开头,为确保索引在 0 到 obj->k 之间循环,所以需要取模处理。
    obj->rear %= (obj->k + 1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) { //删除数据
    if (myCircularQueueIsEmpty(obj))//队列为空返回false
        return false;

    obj->front++;//移动头下标即可
    obj->front %= (obj->k + 1);//因为循环队列,头下标同上方尾下标同理,需要取模处理
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) { //获取队首元素
    if (myCircularQueueIsEmpty(obj))//队列为空返回-1
        return -1;
    return obj->a[obj->front];//队列不为空,直接返回队首元素
}

int myCircularQueueRear(MyCircularQueue* obj) { //获取队尾元素
    if (myCircularQueueIsEmpty(obj))//队列为空返回-1
        return -1;

    // if (obj->rear == 0)
    //     return obj->a[obj->k];
    // else
    //     return obj->a[obj->rear - 1];

    //因为是循环队列,尾下标分2种情况
    //1.尾下标在队列头。 2.尾下标不在队列头
    return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
    //obj->rear-1是队尾元素,obj->k+1是队列空间个数。
    //队尾元素下标+队列空间个数相当于绕了一圈停在原来的位置。
    //之所以要加上obj->k+1,是因为如果rear恰好指向队列头,那么-1操作就会rear就会变成负数。
    //这一步相当于将索引值转化为非负数,以确保后续的取模操作不会得到负数结果
    //所以该操作是为了确保在模运算中得到正确的结果
}

void myCircularQueueFree(MyCircularQueue* obj) { //释放队列
    free(obj->a);//释放队列数组
    free(obj);//释放维护队列信息的结构体
}

第四章:概念选择题

1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺序是( )。

A. 12345ABCDE
B. EDCBA54321
C. ABCDE12345
D. 54321EDCBA
答案:B

2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是()

A. 1, 4, 3, 2
B. 2, 3, 4, 1
C. 3, 1, 4, 2
D. 3, 4, 2, 1
答案:C 

3.循环队列的存储空间为 Q(1:100) ,初始状态为 front=rear=100 。经过一系列正常的入队与退队操作后, front=rear=99 ,则循环队列中的元素个数为( )

A. 1
B. 2
C. 99
D. 0或者100
答案:D

4.以下( )不是队列的基本运算?

A. 从队尾插入一个新元素
B. 从队列中删除第i个元素
C. 判断一个队列是否为空
D. 读取队头元素的值
答案:B

5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设队头不存放数据)

A. (rear - front + N) % N + 1
B. (rear - front + N) % N
C. (rear - front) % (N + 1)
D. (rear - front + N) % (N - 1)

答案:B
解析:有效长度一般是rear-front, 但是循环队列中rear有可能小于front,减完之后可能是负数,所以需要+N,此时结果刚好是队列中有效元素个数,但如果rear大于front,减完之后就是有效元素个数了,再加N后有效长度会超过N,故需要%N。 

6. 下列关于顺序结构实现循环队列的说法,正确的是( )

A.循环队列的长度通常都不固定
B.直接用队头和队尾在同一个位置可以判断循环队列是否为满
C.通过设置计数的方式可以判断队列空或者满
D.循环队列是一种非线性数据结构

答案:C
队列适合使用链表实现,使用顺序结构(即固定的连续空间)实现时会出现假溢出的问题,因此大佬们设计出了循环队列,循环队列就是为了解决顺序结构实现队列假溢出问题的
A错误:循环队列的长度都是固定的
B错误:队头和队尾在同一个位置时 队列可能是空的,也可能是满的,因此无法判断
C正确:设置计数即添加一个字段来记录队列中有效元素的个数,如果队列中有效元素个数等于空间总大小时队列满,如果队列中有效元素个数为0时队列空
D错误:循环队列也是队列的一种,是一种特殊的线性数据结构

7. 下列关于栈的叙述正确的是( )

A.栈是一种“先进先出”的数据结构
B.栈可以使用链表或顺序表来实现
C.栈只能在栈底插入数据
D.栈不能删除数据

答案:B
A错误:栈是一种后进先出的数据结构,队列是先进先出的
B正确:顺序表和链表都可以用来实现栈,不过一般都使用顺序表,因为栈想当于是阉割版的顺序表,只用到了顺序表的尾插和尾删操作,顺序表的尾插和尾删不需要搬移元素效率非常高,故一般都是使用顺序表实现
C错误:栈只能在栈顶进行输入的插入和删除操作
D错误:栈是有入栈和出栈操作,出栈就是从栈中删除一个元素

8. 一个栈的入栈序列为ABCDE,则不可能的出栈序列为( )

A.ABCDE
B.EDCBA
C.DCEBA
D.ECDBA

答案:D
如果是E先出,说明ABCDE都已经全部入栈,E出栈之后,此时栈顶元素是D,如果再要出栈应该是D,而不应该是C。

9. 下列关于用栈实现队列的说法中错误的是( )

A.用栈模拟实现队列可以使用两个栈,一个栈模拟入队列,一个栈模拟出队列
B.每次出队列时,都需要将一个栈中的全部元素导入到另一个栈中,然后出栈即可
C.入队列时,将元素直接往模拟入队列的栈中存放即可
D.入队列操作时间复杂度为O(1)

答案:B
选项B中,一个栈模拟入队列,一个栈模拟出队列,出队列时直接弹出模拟出队列栈的栈顶元素,当该栈为空时,将模拟入队列栈中所有元素导入即可,不是每次都需要导入元素,故错误
选项A中,栈和队列的特性是相反的,一个栈实现不了队列
选项C中,一个栈模拟入队列,一个栈模拟出队列,入队列时,将元素直接往模拟入队列的栈中存放
选项D中,入队列就是将元素放到栈中,因此时间复杂度就是O(1)

10. 链栈与顺序栈相比,比较明显的优点是( )

A.插入操作更加方便
B.删除操作更加方便
C.入栈时不需要扩容

答案:C
A错误,如果是链栈,一般需要进行头插或者头删操作,而顺序栈一般进行尾插和尾删操作,链表的操作比顺序表复杂,因此使用顺序结构实现栈更简单
B错误,原因参考A
C正确,链式结构实现栈时,每次入栈相当于链表中头插一个节点,没有扩容一说

11. 下列关于队列的叙述错误的是( )

A.队列可以使用链表实现
B.队列是一种“先入先出”的数据结构
C.数据出队列时一定只影响尾指针
D.数据入队列时一定从尾部插入

答案:C
出队操作,一定会影响头指针,如果出队之后,队列为空,会影响尾指针。

12. 以下不是队列的基本运算的是( )

A.从队尾插入一个新元素
B.从队列中删除队尾元素
C.判断一个队列是否为空
D.读取队头元素的值

答案:B
队列只能从队头删除元素。

13. 下面关于栈和队列的说法中错误的是( )

A.队列和栈通常都使用链表实现
B.队列和栈都只能从两端插入、删除数据
C.队列和栈都不支持随机访问和随机插入
D.队列是“先入先出”,栈是“先入后出”

答案:A B
A错误:栈是尾部插入和删除,一般使用顺序表实现,队列是头部删除尾部插入,一般使用链表实现
B错误:栈是后进先出,尾部插入和删除;队列是先进先出,尾部插入头部删除
C正确:栈只能访问栈顶元素,不支持随机访问,队列也不支持
D正确:栈和队列的特性

14. 用无头单链表存储队列,其头指针指向队头结点,尾指针指向队尾结点,则在进行出队操作时( )

A.仅修改队头指针
B.队头、队尾指针都要修改
C.队头、队尾指针都可能要修改
D.仅修改队尾指针

答案:C
出队操作,一定会修改头指针,如果出队之后,队列为空,需要修改尾指针。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值