数据结构--(栈、队列实现及3个OJ题)

1:队列的实现

1.1:初始化

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->_size = 0;
}

1.2:销毁

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	pq->_size = 0;
	while (cur)
	{
		QNode* del = cur;
		cur = cur->next;
		free(del);

	}
	pq->head = pq->tail = NULL;
}

1.3:入队列

void QueuePush(Queue* pq, QDataType x)//尾插
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	else
	{
		newnode->data = x;
		newnode->next = NULL;
	}
	if (pq->tail == NULL)
	{
		pq->head = pq->tail = newnode;

	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->_size++;
}

1.4:出队列

void QueuePop(Queue* pq)//头删
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else 
    {
	QNode* del = pq->head;
	pq->head = pq->head->next;
	free(del);
	del = NULL;


     }
	pq->_size--;
}

1.5:取队列的头

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	return pq->head->data;
}

1.6:取队列的尾

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	return pq->tail->data;
}

1.7:判空

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

1.8:取队列长度

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->_size;
}

2:栈的实现

1:初始化

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

2:销毁

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

3:入栈

void StackPush(ST* ps, STDateType x)
{
	if(ps->top == ps->capacity)
	{ 
		int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity * 2);
		STDateType* tmp = (STDateType*)realloc(ps->a, newcapacity*sizeof(STDateType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->top] = x;
	++ps->top;
	
}

4:出栈

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	--ps->top;
}

5:判空

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

6:取size

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

top是栈顶元素的下一个位置,因此top就是size大小。

7:取栈顶元素

STDateType StackTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->a[ps->top - 1];//top是栈顶元素的下一个位置
}

3:OJ题

3.1:用队列实现栈

image-20221002131337015

image-20221002131527007

思路:栈是后进先出队列是先进先出,因此我们的思路是用2个队列,一个为空,一个不为空。当非空队列元素数量大于1的时候,就把非空队列的元素push到空队列里面,然后pop掉非空队列队头的数据,依次循环直到非空队列元素为1,此时pop掉这个元素。

对于谁是空队列谁是非空我们不知道,可以默认队列1为非空,如果队列1不为空那就把非空的位置给队列2。

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);
}

3.2:用栈实现队列

image-20221002132519277

image-20221002132047672

栈优先出栈顶元素,而队列想要pop1,这怎么办?

image-20221002132238094

思路:定义2个栈,一个栈为专门出数据,一个专门为入数据,可以看到,当入数据的这个栈为空就把出数据的栈里的所有数据导入到入数据的栈,然后再pop,就等于队列的先进先出

typedef struct {
ST Pushstack;
ST Popstack;

} MyQueue;


MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->Pushstack);
StackInit(&obj->Popstack);
return obj;
}
void pushtopop(MyQueue* obj)
{
    if(StackEmpty(&obj->Popstack))
    {
        while(!StackEmpty(&obj->Pushstack))
        {
          StackPush(&obj->Popstack,StackTop(&obj->Pushstack));
          StackPop(&obj->Pushstack);
        }
    }
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->Pushstack,x);
}

int myQueuePop(MyQueue* obj) {
pushtopop(obj);
int front = StackTop(&obj->Popstack);
StackPop(&obj->Popstack);
return front;
}

int myQueuePeek(MyQueue* obj) {
pushtopop(obj);
return StackTop(&obj->Popstack);

}

bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->Popstack) && StackEmpty(&obj->Pushstack);
}

void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->Popstack);
StackDestroy(&obj->Pushstack);
free(obj);

}

3.3:设计循环队列

image-20221002132535968

image-20221002132757929

我们首先考虑使用哪种结构?

如果使用链表,back是末端元素的下一个位置,如果back在中间,取队尾元素就比较麻烦,因为要让back指向back的上一个节点,单链表不行,因此采用数组

如果back到了末尾,继续++则越界,如何回到下标为0的位置?可以使用%=的运算方式。

代码实现如下:

typedef struct {
int* a;
int front;
int back;
int N;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int)*(k+1));
obj->front = obj->back = 0;
obj->N = k+1;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front ==  obj->back;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
return ((obj->back+1) % obj->N) == obj->front;

}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
{
    return false;
}
else
{
    obj->a[obj->back] = value;
    obj->back++;
    obj->back %= obj->N;
    return true;
}
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
    return false;
}
else
{
  obj->front++;
  obj->front %= obj->N;   
  return true;
}

}

int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
    return -1;
}
else
{
    return obj->a[obj->front];
}
}

int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
    return -1;
}
else
{
    return obj->a[(obj->back+obj->N-1)% obj->N];
}
}



void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不熬夜不抽烟不喝酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值