【C习题】栈与对列

一.对列实现栈

题目描述:
在这里插入图片描述

关键思路:
要实现的栈有两个对列
当栈出数据时:先把存数据的栈里面的数据一个一个移到另一个栈,直到存数据的栈只有一个数据为止。然后再把最后一个元素出栈。
细节1:存数据的栈移到另一个栈这个过程,需要把栈里面存过的数据出栈。
细节2:只有一个数据的条件是头指针与尾指针相等
补充:
1.判断此栈为空需要判断两个对列都为空
2.释放栈时需要先释放里面的对列,再释放栈
3.出栈的时候需要判断两个对列都不为空的,入栈的时候则不需要考虑。

这是我们所需对列的代码,还得手搓,有需要的直接复制即可。

typedef int QDataType;
typedef struct QListNode
{
	QDataType val;
	struct QListNode* next;
}QListNode;
typedef struct Queue
{
	QListNode* head;
	QListNode* tail;
}Queue;
void QueueInit(Queue* q)
{
	assert(q);
	q->head = NULL;
	q->tail = NULL;
}
void QueuePush(Queue* q, QDataType data)
{
	assert(q);
	if (q->head == NULL)
	{
		QListNode* NewNode = (QListNode*)malloc(sizeof(QListNode));
		NewNode->val = data;
		q->head = q->tail = NewNode;
		q->head->next = q->tail->next = NULL;
	}
	else
	{
		QListNode* NewNode = (QListNode*)malloc(sizeof(QListNode));
		q->tail->next = NewNode;
		NewNode->val = data;
		NewNode->next = NULL;
		q->tail = NewNode;
	}
}

void QueueDestroy(Queue* q)
{
	assert(q);
	QListNode* cur = q->head;
	while (cur != NULL)
	{
		QListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;
}
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head);
	if (q->head == q->tail)
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else
	{
		QListNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
}
QDataType QueueFront(Queue* q)
{

	assert(q);
	assert(q->head);
	return q->head->val;
}
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->val;
}
int QueueSize(Queue* q)
{
	assert(q);
	assert(q->head);
	QListNode* cur = q->head;
	int count = 0;
	while (cur)
	{
		QListNode* next = cur->next;
		count++;
		cur = next;
	}
	return count;
}
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->head == NULL;
}

这是题目让我们写的代码

typedef struct
{
    Queue one;
    Queue two;
} MyStack;
MyStack* myStackCreate() 
{
    MyStack* stack =(MyStack *)malloc(sizeof(MyStack));
    if(stack == NULL)
    {
        perror("malloc stack");
        exit(-1);
    }
    QueueInit(&stack->one);
    QueueInit(&stack->two);
    return stack;
}
void myStackPush(MyStack* obj, int x) 
{
    assert(obj);
    //假设一个对列为空
    Queue* Empty = &obj->one; 
    Queue* NoEmpty = &obj->two;
    //如果一个对列不为空
    if(Empty->head != NULL)
    {
        Empty = &obj->two;
        NoEmpty = &obj->one;
    }
    QueuePush(NoEmpty,x);
}

int myStackPop(MyStack* obj) 
{
    assert(obj);
    //假设一个对列为空
    Queue* Empty = &obj->one; 
    Queue* NoEmpty = &obj->two;
    //倘若两个对列都为空呢?
    assert(NoEmpty->head||Empty->head);//都为空才为空。
    //如果一个对列不为空
    if(Empty->head != NULL)
    {
        Empty = &obj->two;
        NoEmpty = &obj->one;
    }
    //移剩下一个结点
    while(NoEmpty->head!=NoEmpty->tail)
    {
        QueuePush(Empty,QueueFront(NoEmpty));
        QueuePop(NoEmpty);//释放的是不为空的对列
    }
    QDataType x = QueueFront(NoEmpty);
    QueuePop(NoEmpty);
    return x;   
}

int myStackTop(MyStack* obj) 
{
    assert(obj);
    //假设一个对列为空
    Queue* Empty = &obj->one; 
    Queue* NoEmpty = &obj->two;
    if(NoEmpty->head!=NULL)
    {
        return QueueBack(NoEmpty);//栈返回的是对列的最后一个元素
    }
    else
    {
        return QueueBack(Empty);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    assert(obj);
    return QueueEmpty(&obj->one)&&QueueEmpty(&obj->two);
}

void myStackFree(MyStack* obj) 
{
    QueueDestroy(&obj->one);
    QueueDestroy(&obj->two);
    free(obj);
}

二.栈实现对列

题目描述:
在这里插入图片描述
关键思路:

出栈思路:
这里的存数据与出数据的栈是固定的,当出数据的栈为空时,再从入数据的栈里面拿数据,否则不能拿数据,而入数据的栈则可以一直入。
实现小技巧:先实现myQueuePeek再实现myQueuePop会简单很多
释放栈的思路:
先释放对列里面的栈,再释放栈。
细节:函数要调用下面的函数,要不就声明一下,要不就把下面的函数放在此函数的上面。

这是我们所需栈的代码,还得手搓,有需要的直接复制即可。

typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int size;
	int capacity;
}Stack;
void StackInit(Stack* ps)
{
	ps->arr = NULL;
	ps->capacity = 0;
	ps->size = 0;
}

void StackPush(Stack* ps, STDataType data)
{
	if (ps->capacity == 0 || ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->arr,sizeof(STDataType)*newcapacity);
		if (tmp == NULL)
		{
			perror("StackPush:realloc");
			return;
		}
		else
		{
			ps->arr = tmp;
			ps->capacity = newcapacity;
		}
	}
	ps->arr[ps->size++] = data;
}
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->size > 0);
	ps->arr[ps->size - 1];
	ps->size--;
}
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->size > 0);
	return ps->arr[ps->size - 1];
}
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->size;
}
int StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->size == 0;
}
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = 0;
	ps->size = 0;
}

这是目标代码

typedef struct 
{
    Stack PopStack;
    Stack PushStack;
} MyQueue;

MyQueue* myQueueCreate() 
{
    MyQueue *newQueue = (MyQueue *)malloc(sizeof(MyQueue));
    if(newQueue==NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    StackInit(&newQueue->PopStack);
    StackInit(&newQueue->PushStack);
    return newQueue;
}

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

int myQueuePeek(MyQueue* obj) 
{
    Stack *Pop = &obj->PopStack;
    Stack *Push =&obj->PushStack;
    if(StackEmpty(Pop))
    {
        while(!StackEmpty(Push))
        {
            StackPush(Pop,StackTop(Push));
            StackPop(Push);
        }
    }
    return StackTop(Pop);
}
int myQueuePop(MyQueue* obj) 
{

    STDataType x = myQueuePeek(obj);
    StackPop(&obj->PopStack);
    return x;
}
bool myQueueEmpty(MyQueue* obj) {
    assert(obj);
    return StackEmpty(&obj->PopStack)&&StackEmpty(&obj->PushStack);
}
void myQueueFree(MyQueue* obj) 
{
    StackDestroy(&obj->PopStack);
    StackDestroy(&obj->PushStack);
    free(obj);
}

三.循环对列

题目描述:
在这里插入图片描述

顺序表思路:
设置k的长度,要多设置一个,所以实际开辟的长度为k+1
判断对列是否已满:
两种方法:
菜鸡法:
第一种情况:头减尾等于对列长度k
第二种情况:尾减头等于1
大佬的方法:
尾下标加1模上对列长度加一等于头下标
说明:%在这里实际就是达到了循环,并且处理了菜鸡的第一种情况。
返回队尾元素
先判断对列是否为空
然后有两种方法返回
菜鸡法:
第一种情况:尾下标为0返回对列长度k也就是最后一个元素的下标。
注意:我们可是多开了一个元素的哦!
第二种情况:返回尾下标减一
大佬法:
返回尾下标加对列长度模上对列长度加1
注意的细节:
1.为了让对列达到循环的效果每次我们都得模上对列的长度加1
2.释放对列的时候我们要先释放对列里面的顺序表再释放对列!

typedef int QDataType;
typedef struct 
{
    QDataType *arr;
    int head;
    int tail;
    int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue *newQueue =(MyCircularQueue *)malloc(sizeof(MyCircularQueue));
    if(newQueue==NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    QDataType* tmp = (QDataType*)malloc(sizeof(QDataType)*(k+1));
    if(tmp==NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    newQueue->arr = tmp;
    newQueue->tail=newQueue->head=0;
    newQueue->k=k;
    return newQueue;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) 
{    
   //if((obj->tail+1)%(obj->k+1)==obj->head)
   //{
   //    return true;
   // }
   //如何分开算?可以拿笔验证一下。
   if(obj->head-obj->tail==1||obj->tail-obj->head==obj->k)
   {
       return true;
   }
   return false;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->head-obj->tail==0;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
   assert(obj);
   //对列是否已满
   if(myCircularQueueIsFull(obj))
   {
       return false;
   }
   obj->arr[obj->tail++]=value;
   obj->tail%=(obj->k+1);
   return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->head++;
    obj->head%=(obj->k+1);
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->arr[obj->head];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    if(obj->tail==0)//特殊情况
    {
        return obj->arr[obj->k];
    }
    else
    {
        return obj->arr[obj->tail-1];
    }
   //return obj->tail == 0 ? obj->arr[obj->k] : obj->arr[obj->tail-1];
  //return obj->arr[(obj->tail+obj->k)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) 
{
    assert(obj);
    free(obj->arr);
    obj->arr = NULL;
    free(obj);
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值