力扣刷题之 栈和队列 相互实现(力扣225 力扣232)

  个人主页:欢迎大家光临——>沙漠下的胡杨

  各位大帅哥,大漂亮

 如果觉得文章对自己有帮助

 可以一键三连支持博主

 你的每一分关心都是我坚持的动力

 

 ☄: 本期重点:力扣225 力扣232

  希望大家每天都心情愉悦的学习工作。 


       目录      

用队列实现栈(力扣225):

代码实现:

插入:

初始化:

入栈:

删除栈顶元素并返回值:

 返回栈顶元素:

判断栈是否为空:

栈的销毁:

整体代码(包含队列的创建):

用栈实现队列(力扣 232):

代码实现:

队列的创建,初始化和销毁

判断队列是否为空:

队列的插入:

从队列的开头移除并返回元素:

返回队列开头元素:

整体代码:


在前几天学习了栈和队列,关于栈和队列的特性我们还不是很熟练,今天我们一起做两道题,分别是用队列实现栈,和用栈实现队列,来进一步强化下所学习的知识吧。

用队列实现栈(力扣225):

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第1张图片

这是题目,就是在不考虑效率的情况下,使用队列模拟实现栈的性质,我们使用的语言依然是 纯C ,所以我们在这之前还是要先写出一个队列出来的,我就借用之前文章的栈和队列来实现了。(队列实现)(栈的实现)

我们分析先下如何实现呢?

队列是先进先出,我们要实现先进后出,我们可以用两个队列,一个队列用来存储数据,一个队列用来倒数据,先把数据放入一个队列中,然后再把除了最后一个数据的其他数据放入另一个队列中,使原本队列只剩一个数据,然后删除,循环倒数据即可实现栈的功能。

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第2张图片 

代码实现:

 下面我们来实现函数接口吧:

插入:

typedef struct 
{
    Queue q1;
    Queue q2;
} MyStack;//创建结构

 创建时我们可以直接进行创建两个队列,方便倒数据。

初始化:

MyStack* myStackCreate() //初始化,并返回一个结点
{
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);

    return obj;
}

 我们必须要 malloc 一个所谓的栈的空间,因为最后要返回这个结构的指针,这个函数要销毁,如果返回栈空间地址,地址值无效,指针就无效了。

然后在一个个初始化这个 q1和q2队列就好了。

 

入栈:

void myStackPush(MyStack* obj, int x)//入栈
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

 入栈时比较简单,我们就向队列中有元素的中存放就可以啦。如果都为空,那就无所谓。

 

删除栈顶元素并返回值:

int myStackPop(MyStack* obj) //删除栈顶数据,并返回
{
    Queue* Empty = &obj->q1;
    Queue* NoEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        Empty = &obj->q2;
        NoEmpty = &obj->q1;
    }

    while(QueueSize(NoEmpty)>1)
    {
        QueuePush(Empty,QueueFront(NoEmpty));
        QueuePop(NoEmpty);
    }

    int top = QueueFront(NoEmpty);
    QueuePop(NoEmpty);

    return top;
}

我们首先使用假设法,得到为空的队列和不为空的队列,我们把这个不为空的队列向为空的队列中插入,然后pop掉不为空队列的首元素,一直到这个队列元素数量为 1 时停止,最后我们把原先不为空的队列的元素的唯一一个元素取出来,然后在pop掉,这样原来不为空的队列就为空了,其他的元素也通过插入放入了原来不为空的队列中了。

 

 返回栈顶元素:

int myStackTop(MyStack* obj)//返回栈顶元素 
{
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

我们就判断那个队列不为空,栈顶的元素就是不为空队列的最后一个元素。

 

判断栈是否为空:

 

bool myStackEmpty(MyStack* obj) //判断栈是否为空
{
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

只有两个队列都为空时,栈才是空的,所以用 并(&&)来判断。

  

栈的销毁:

void myStackFree(MyStack* obj) //销毁栈
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);

    free(obj);
}

 因为我们创建时就是创建的 obj 的空间,在逐步创建的q1 和 q2 的空间,所以我们在释放时,我们也该先释放q1 和 q2的空间,如果先释放 obj ,那么就找不到q1 q2了。

整体代码(包含队列的创建):


typedef int QDataType;
 
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
 
typedef struct Queue
{
	QNode* head;
	QNode* tail;
}Queue;
 
void QueueInit(Queue* qp);//初始化
 
void QueueDestroy(Queue* qp);//队列的销毁
 
void QueuePush(Queue* qp,QDataType x);//队列插入
 
void QueuePop(Queue* qp);//队列删除
 
QDataType QueueFront(Queue* qp);//取出队列首元素
 
QDataType QueueBack(Queue* qp);//取出队列末尾元素
 
bool QueueEmpty(Queue* qp);//判断队列是否为空
 
int QueueSize(Queue* qp);//返回队列的元素个数

 
void QueueInit(Queue* qp)//初始化
{
	assert(qp);
 
	qp->head = qp->tail = NULL;
}
 
void QueueDestroy(Queue* qp)//队列的销毁
{
	assert(qp);
	QNode* cur = qp->head;
 
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
 
	qp->head = qp->tail = NULL;
 
}
 
void QueuePush(Queue* qp,QDataType x)//队列插入
{
	assert(qp);
	QNode *newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail\n");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = x;
	
	if (qp->head == NULL)
	{
		qp->head = qp->tail = newnode;
	}
	else
	{
		qp->tail->next = newnode;
		qp->tail = newnode;
	}
 
}
 
void QueuePop(Queue* qp)//队列删除
{
	assert(qp);
	assert(!QueueEmpty(qp));
 
	if (qp->head->next == NULL)
	{
		qp->head = qp->tail = NULL;
	}
	else
	{
		QNode* next = qp->head->next;
		free(qp->head);
		qp->head = next;
	}
}
 
QDataType QueueFront(Queue* qp)//取出队列首元素
{
	assert(qp);
	assert(!QueueEmpty(qp));
 
	return qp->head->data;
}
 
QDataType QueueBack(Queue* qp)//取出队列末尾元素
{
	assert(qp);
	assert(!QueueEmpty(qp));
 
	return qp->tail->data;
}
 
bool QueueEmpty(Queue* qp)//判断队列是否为空
{
	assert(qp);
 
	return qp->head == NULL;
}
 
int QueueSize(Queue* qp)//返回队列的元素
{
	assert(qp);
	int size = 0;
	QNode* cur = qp->head;
 
	while (cur)
	{
		++size;
		cur = cur->next;
	}
 
	return size;
}
typedef struct 
{
    Queue q1;
    Queue q2;
} MyStack;//创建结构


MyStack* myStackCreate() //初始化,并返回一个结点
{
    MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&obj->q1);
    QueueInit(&obj->q2);
    return obj;
}

void myStackPush(MyStack* obj, int x)//入栈
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) //删除栈顶数据,并返回
{
    Queue* Empty = &obj->q1;
    Queue* NoEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        Empty = &obj->q2;
        NoEmpty = &obj->q1;
    }

    while(QueueSize(NoEmpty)>1)
    {
        QueuePush(Empty,QueueFront(NoEmpty));
        QueuePop(NoEmpty);
    }

    int top = QueueFront(NoEmpty);
    QueuePop(NoEmpty);

    return top;
}

int myStackTop(MyStack* obj)//返回栈顶元素 
{
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) //判断栈是否为空
{
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) //销毁栈
{
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);

    free(obj);
}

下面我们看下它的兄弟题目

用栈实现队列(力扣 232):

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第3张图片

我们是使用栈来模拟实现队列相关的操作,和上面的类似,我们也要有两个栈,但是我们不需要频繁的倒数据,我们创建一个Push栈,一个Pop栈,Push栈就插入数据,Pop栈就是出数据,如果Pop栈为空,那么我们就先Push栈中要数据,就是把Push栈的数据倒过来就好2了,其他和上面题类似。

入数据:

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第4张图片  

 该出数据时:

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第5张图片

在插入数据,删除数据

力扣刷题之 栈和队列 相互实现(力扣225 力扣232)_第6张图片就是Push栈一直入数据,Pop一直出数据,如果Pop为空,那么就把Push栈的数据倒到Pop栈中,这样循环实现。

代码实现:

还是要先写一个栈,然后在进行操作。

队列的创建,初始化和销毁

typedef struct //初始化
{
    ST Pushst;
    ST Popst;
} MyQueue;


MyQueue* myQueueCreate() //初始化
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&obj->Pushst);
    StackInit(&obj->Popst);

    return obj;
}

void myQueueFree(MyQueue* obj)//销毁
{
    StackDestroy(&obj->Pushst);
    StackDestroy(&obj->Popst);

    free(obj);
}

 这些都和上面的类似不在赘述。

 

判断队列是否为空:

bool myQueueEmpty(MyQueue* obj) //判空
{
    return StackEmpty(&obj->Pushst) && StackEmpty(&obj->Popst);
}

也是和上面类似,只有两个栈为空,队列才是空的。

 

队列的插入:

void myQueuePush(MyQueue* obj, int x)//插入
{
    StackPush(&obj->Pushst,x);
}

 队列的插入,只要插入Push栈就可以啦。

 

从队列的开头移除并返回元素:

int myQueuePop(MyQueue* obj)//从队列的开头移除并返回元素

{
    if(StackEmpty(&obj->Popst))
    {
        while(!StackEmpty(&obj->Pushst))
        {
            StackPush(&obj->Popst,StackTop(&obj->Pushst));
            StackPop(&obj->Pushst);
        }
    }
    int top = StackTop(&obj->Popst);
    StackPop(&obj->Popst);
    return top;
}

这个只需要判断Pop栈是否为空,如果为空就从Push栈倒数据,不为空就直接保存Pop栈的头元素,然后Pop掉,接着返回就好了。

 

返回队列开头元素:

int myQueuePeek(MyQueue* obj) 
{
    if(StackEmpty(&obj->Popst))
    {
        while(!StackEmpty(&obj->Pushst))
        {
            StackPush(&obj->Popst,StackTop(&obj->Pushst));
            StackPop(&obj->Pushst);
        }
    }
     
    return StackTop(&obj->Popst);
}

  同上,比起上面的是我们不需要Pop栈顶元素,所以可以直接返回。

整体代码:

typedef int STDataType;
 
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
 
void StackInit(ST* ps);//初始化
 
void StackDestroy(ST* ps);//销毁
 
void StackPush(ST* ps, STDataType x);//插入(入栈),栈的插入是尾插。
 
void StackPop(ST* ps);//删除(出栈),从尾部删除。
 
STDataType StackTop(ST* ps);//读出栈顶
 
bool StackEmpty(ST* ps);//判断栈是否为空
 
int StackSize(ST* ps);//栈中的元素个数 
 
void StackInit(ST* ps)//初始化
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
 
void StackDestroy(ST* ps)//销毁
{
	assert(ps);
 
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
 
void StackPush(ST* ps, STDataType x)//插入(入栈),栈的插入是尾插。
{
	assert(ps);
 
	if (ps->capacity == ps->top)
	{
		int NewCapaticy = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType)*NewCapaticy);
		if (tmp == NULL)
		{
			perror("realoc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = NewCapaticy;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
 
void StackPop(ST* ps)//删除(出栈),从尾部删除。
{
	assert(ps);
	assert(!StackEmpty(ps));
 
	ps->top--;
}
 
STDataType StackTop(ST* ps)//读出栈顶
{
	assert(ps);
	assert(!StackEmpty(ps));
 
	return ps->a[ps->top-1];
}
 
bool StackEmpty(ST* ps)//判断栈是否为空
{
	assert(ps);
 
	return ps->top == 0;
}
 
int StackSize(ST* ps)//栈中的元素个数
{
	assert(ps);
 
	return ps->top;
}

typedef struct //初始化
{
    ST Pushst;
    ST Popst;
} MyQueue;


MyQueue* myQueueCreate() 
{
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&obj->Pushst);
    StackInit(&obj->Popst);

    return obj;
}

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


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

int myQueuePeek(MyQueue* obj) 
{
    if(StackEmpty(&obj->Popst))
    {
        while(!StackEmpty(&obj->Pushst))
        {
            StackPush(&obj->Popst,StackTop(&obj->Pushst));
            StackPop(&obj->Pushst);
        }
    }
     
    return StackTop(&obj->Popst);
}

bool myQueueEmpty(MyQueue* obj) 
{
    return StackEmpty(&obj->Pushst) && StackEmpty(&obj->Popst);
}

void myQueueFree(MyQueue* obj)//销毁
{
    StackDestroy(&obj->Pushst);
    StackDestroy(&obj->Popst);

    free(obj);
}

本期到这里结束啦,明天再见!

你可能感兴趣的:(C语言刷题笔记,数据结构,leetcode,数据结构,算法)