刷题笔记(栈和队列篇)(跑路人笔记)

文章目录

  • 前言
  • 用栈实现队列
    • 大致思路
    • 正确代码
    • 函数功能及注意点讲解
  • 用队列实现栈
    • 大致思路
    • 队列的代码
    • 正确代码
    • 函数思想讲解和注意事项
  • 结尾

前言

进入栈和队列之后必须马上开始我的练习.
下面是两个力扣的简单题目.
分别是用栈实现队列
和用队列实现栈
这两道题倒是都不难,但是对于刚刚进入栈和队列学习的朋友还是有些意思和锻炼的.
总的来说,值得一搞.
防止有人忘记了:

栈: 后来的先出.
队列: 像排队一样先来先出.

用栈实现队列

栈实现队列
刷题笔记(栈和队列篇)(跑路人笔记)_第1张图片

大致思路

通过两个栈来实现队列的功能函数实现,
如顺序输入:
12345
我们栈是54321顺序出
队列是12345顺序出
我们可以用两个栈将12345的输入12345输出
比如一个栈存储12345,我们把这些数据一个个输入到另一个栈中那么另一个栈就存储了54321.这样我们从另一个栈读取数据时就是12345的读取了,也就符合了我们对队列的需要.

当然我们用c来实现这个问题的时候我们需要栈的函数接口博主就分享给大家

typedef int STDateType;
typedef struct Stack
{
	int top;
	int capacity;
	STDateType* date;
}ST;
void StackInit(ST* stack)
{
	stack->date = malloc(sizeof(ST) * 4);
	stack->capacity = 4;
	stack->top = 0;
}
void StackDestroy(ST* stack)
{
	free(stack->date);
	stack->date = NULL;
	stack->top = stack->capacity = 0;
}
void StackPush(ST* stack, STDateType x)
{
	assert(stack);
	if (stack->top == stack->capacity)
	{
		STDateType* new = realloc(stack->date, (size_t)stack->capacity * 2);
		if (new == NULL)
		{
			perror("StackPush new \n");
			exit(-1);
		}
		else
		{
			stack->date = new;
		}
	}
		stack->date[stack->top] = x;
		stack->top++;
}
void StackPop(ST* stack)
{
	assert(stack);
	if (stack->top >0 )
	{
		stack->top--;
	}
	else
	{
		printf("栈为空不能删除\n");
		return;
	}
}

STDateType StackTop(ST* stack)
{
	assert(stack);
	assert(stack->top > 0);
	return stack->date[stack->top-1];
}

int StackSize(ST* stack)
{
	assert(stack);
	return stack->top;
}

bool StackEmpty(ST* stack)
{
	assert(stack);
	return stack->top == 0;
}

这些函数接口都在我之前的博客栈和队列(跑路人笔记)中有讲解.

正确代码

typedef struct 
{
    ST push;
    ST pop;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&obj->push);
    StackInit(&obj->pop);
    return obj;
}

void myQueuePush(MyQueue* obj, int x) 
{
    assert(obj);
    StackPush(&obj->push,x);
}

int myQueuePop(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->pop))
    {
        while(!StackEmpty(&obj->push))
        {
            int top = StackTop(&obj->push);
            StackPush(&obj->pop,top);
            StackPop(&obj->push);
        }
    }
    int ret = StackTop(&obj->pop);
    StackPop(&obj->pop);
    return ret;

}

int myQueuePeek(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->pop))
    {
        while(!StackEmpty(&obj->push))
        {
            int top = StackTop(&obj->push);
            StackPush(&obj->pop,top);
            StackPop(&obj->push);
        }
    }
    return StackTop(&obj->pop);
}

bool myQueueEmpty(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->push)&&StackEmpty(&obj->pop))
    {
        return true;
    }
    else
    {
        return false;
    }
}

void myQueueFree(MyQueue* obj) 
{
    assert(obj);
    StackDestroy(&obj->pop);
    StackDestroy(&obj->push);
    free(obj);
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

函数功能及注意点讲解

typedef struct 
{
    ST push;
    ST pop;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    assert(obj);
    StackInit(&obj->push);
    StackInit(&obj->pop);
    return obj;
}

(ST是栈结构的变量结构体)结构体里一个用于接收数据一个用于删除和推出数据.

MyQueue* myQueueCreate();

这个函数是用来我们队列部分的创建和初始化.然后将我们创建好的变量返回
值得注意的是

obj需要在堆区开辟,不然出了函数就没有了.
StackInit是我们自己的栈函数传参时要记得取地址.
obj的空指针判断可以有也可以没有因为后面的会有对obj的判空.

void myQueuePush(MyQueue* obj, int x) 
{
    assert(obj);
    StackPush(&obj->push,x);
}

int myQueuePop(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->pop))
    {
        while(!StackEmpty(&obj->push))
        {
            int top = StackTop(&obj->push);
            StackPush(&obj->pop,top);
            StackPop(&obj->push);
        }
    }
    int ret = StackTop(&obj->pop);
    StackPop(&obj->pop);
    return ret;
}

push的时候就很简单放入obj->push里就完事.
删除时
当obj->pop为空的时候就直接吧obj->push的所用元素全部都放到pop里.
然后根据题目要求要把顶部元素返回就可以直接在obj->pop的栈顶元素返回即可.

int myQueuePeek(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->push)&&StackEmpty(&obj->pop))
    {
    	printf("队列为空无元素\n");
        return -1;
    }
    if(StackEmpty(&obj->pop))
    {
        while(!StackEmpty(&obj->push))
        {
            int top = StackTop(&obj->push);
            StackPush(&obj->pop,top);
            StackPop(&obj->push);
        }
    }
    return StackTop(&obj->pop);
}

bool myQueueEmpty(MyQueue* obj) 
{
    assert(obj);
    if(StackEmpty(&obj->push)&&StackEmpty(&obj->pop))
    {
        return true;
    }
    else
    {
        return false;
    }
}

void myQueueFree(MyQueue* obj) 
{
    assert(obj);
    StackDestroy(&obj->pop);
    StackDestroy(&obj->push);
    free(obj);
}

myQueuePeek是得到队列顶的元素.

这个if条件是防止pop内元素为空.
当obj->pop内的元素为空时.
我们要把存储在obj->push内的元素转移到obj->pop中.
如果pop和push都没有元素可以加个if条件.

myQueueEmpty

obj内无元素的时候返回true.

myQueueFree

将两个栈的元素全部free咯.
记得吧obj free了.

无了=-=.

用队列实现栈

用队列实现栈.
其实和用栈实现队列及其的相似‍.能看懂第一题的可以用这道题来试验一下自己的学习成功.
用队列实现栈相对用栈实现队列要效率低一些.

大致思路

通过两个队列来实现栈.
队列实现栈.
队列打入顺序为
12345时读取数据时12345
但是我们的栈要的顺序是54321.
两个队列时我们用和上一题同样的思路是不行的.
但是我们可以留下一个数据比如
p1存放12345.
p2存放:无.
将p1的元素的除最后一个元素放入到p2中
操作后如下
p1: 5
p2: 1234
然后我们将p1的值给出就可.

队列的代码

typedef int QDatetype;
typedef struct QueueNode
{
	int date;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
}
void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}
void QueuePush(Queue* pq,QDatetype x)
{
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = (QNode*)malloc(sizeof(QNode));
		if (pq->tail == NULL)
		{
			exit(-1);
		}
		pq->head->date = x;
		pq->tail->next = NULL;
	}
	else
	{
		QNode* tail = pq->tail;
		QNode* newnode = (QNode*)malloc(sizeof(QNode));
		if (newnode == NULL)
		{
			printf("ʧ\n");
			exit(-1);
		}
		newnode->date = x;
		newnode->next = NULL;
		tail->next = newnode;
		pq->tail = newnode;
	}
}
void QueuePop(Queue* pq)
{
	assert(pq);
	if (pq->head == pq->tail)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

size_t QueueSize(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}

	return size;
}

QDatetype QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->head);

	return pq->head->date;
}

QDatetype QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->date;
}

这部分是我手搓的队列,用不习惯的可以改改.

正确代码

typedef struct 
{
    Queue p1;
    Queue p2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack* ST = (MyStack*)malloc(sizeof(MyStack));
    assert(ST);
    QueueInit(&ST->p1);
    QueueInit(&ST->p2);
    return ST;
}

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->p1))
    {
        QueuePush(&obj->p1,x);
    }
    else
    {
        QueuePush(&obj->p2,x);
    }
}

int myStackPop(MyStack* obj)
{
    Queue* empty = &obj->p1;
    Queue* nonEmpty = &obj->p2;
    if(!QueueEmpty(empty))
    {
        empty = &obj->p2;
        nonEmpty = &obj->p1;
    }
    while(QueueSize(nonEmpty)>1)
    {
        int num = QueueFront(nonEmpty);
        QueuePush(empty,num);
        QueuePop(nonEmpty);
    }
    int ret = QueueFront(nonEmpty);
    QueuePop(nonEmpty);
    return ret;
}

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&obj->p1))
    {
       return QueueBack(&obj->p1);
    }
    else
    {
        return QueueBack(&obj->p2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    if(QueueEmpty(&obj->p1)&&QueueEmpty(&obj->p2))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void myStackFree(MyStack* obj) 
{
    QueueDestory(&obj->p1);
    QueueDestory(&obj->p2);
    free(obj);
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

函数思想讲解和注意事项

typedef struct 
{
    Queue p1;
    Queue p2;
} MyStack;


MyStack* myStackCreate() 
{
    MyStack* ST = (MyStack*)malloc(sizeof(MyStack));
    assert(ST);
    QueueInit(&ST->p1);
    QueueInit(&ST->p2);
    return ST;
}

结构体

结构体里装着两个队列时设计好的结构类型.

MyStack* myStackCreate()

这个函数还是简单的初始化两个队列和结构体的栈类型变量的实现

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->p1))
    {
        QueuePush(&obj->p1,x);
    }
    else
    {
        QueuePush(&obj->p2,x);
    }
}

int myStackPop(MyStack* obj)
{
    Queue* empty = &obj->p1;
    Queue* nonEmpty = &obj->p2;
    if(!QueueEmpty(empty))
    {
        empty = &obj->p2;
        nonEmpty = &obj->p1;
    }
    while(QueueSize(nonEmpty)>1)
    {
        int num = QueueFront(nonEmpty);
        QueuePush(empty,num);
        QueuePop(nonEmpty);
    }
    int ret = QueueFront(nonEmpty);
    QueuePop(nonEmpty);
    return ret;
}

栈的推送

推送的时候我们要保证一个队列是空的这样才能达到我们想要的目的.
所以我们用if条件句来判断那个队列不为空,不为空就将元素放到他那里这样就就可以保证一个队列是完全空的了.

为啥要保证一个队列是空的呢?
在pop的时候就知道了

原先的思路就是将有元素的队列内的除倒数第一个元素外都转移到另一个空的队列中.
然后将最后一个元素返回,再删除去最后的元素.这样我们的队列就又有一个为空了,可以循环使用下去了.
注意事项
我们要得到空和非空的队列假设是p1然后再通过if来判断是p1还是p2
记得将最后一个元素pop掉哦~.

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&obj->p1))
    {
       return QueueBack(&obj->p1);
    }
    else
    {
        return QueueBack(&obj->p2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    if(QueueEmpty(&obj->p1)&&QueueEmpty(&obj->p2))
    {
        return true;
    }
    else
    {
        return false;
    }
}

void myStackFree(MyStack* obj) 
{
    QueueDestory(&obj->p1);
    QueueDestory(&obj->p2);
    free(obj);
}

栈顶元素的获得

其实很简单直接看非空队列的队尾数就好

判断是否为空

两个队列都为空及为空,否则就不为空.

队列摧毁

将两个队列都摧毁后free掉obj即可.

结尾

舒文想要机器人呜呜呜呜呜呜呜呜呜呜

你可能感兴趣的:(数据结构刷题,动态规划,c语言,算法)