[Data structure] stack and queue classic example - pure C

 s​​​​​​​20. Valid parentheses

Using the stack to solve the problem described by the title is the optimal solution.

Ideas: 1) Find the left brackets, push them into the stack, and start popping the stack when encountering the right brackets. If the matching criteria are not met, return false

2) During the matching process, the data in the stack is empty but the data needs to be fetched from the station. After the traversal of the string is completed, the data in the stack is not empty, which requires additional consideration.

Drawing:

Additional processing for idea 2

Code:

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

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

//销毁
void StackDestroy(Stack* ps)
{
	
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

//入栈
void StackPush(Stack* ps, STDataType x)
{
	//断言
	assert(ps);
	//判断是否需要扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? ps->capacity = 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		//判断扩容是否成功
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	//插入数据
	//数组的下标从0开始,top指向的就是栈顶
	ps->a[ps->top] = x;
	ps->top++;
}

//出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//断言栈是否为空
	assert(ps->top > 0);

	ps->top--;
}

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
	//断言栈是否为空
	assert(ps->top);

	return ps->a[ps->top-1];
}

//检测栈是否为空
bool StackEmpty(Stack* ps)
{
	assert(ps);
	非空
	//if (ps->top > 0)
	//{
	//	return false;
	//}
	为空
	//else
	//	return true;
	//更优化的写法
	return ps->top == 0;
}

int StackSize(Stack* ps)
{
	assert(ps);
	//返回个数,top指的是栈顶数据的下一位。
	return ps->top;
}

bool isValid(char * s){
    Stack st;
    StackInit(&st);//初始化
    while(*s!='\0')//遍历
    {
        if(*s=='{'||*s=='['||*s=='(')
        {
            StackPush(&st,*s);//当为{,[,( 时入栈
            s++;//更新
        }
        else
        {
            if(!StackEmpty(&st))//当栈不为空时
            {
            char top = StackTop(&st);//取出栈顶数据
            StackPop(&st);//删除栈顶数据
            if((top == '{'&& *s!='}')||(top == '('&&*s!=')'||top == '['&&*s!=']'))//如果不匹配,就返回false
            {
                return false;
            }
            else
            {
                s++;
            }
            }
            else//当栈为空时,说明其缺少左括号,必然不能配对
            return false;
        }

    }
    //循环结束时
    int ret = StackEmpty(&st);//记录栈是否为空
    StackDestroy(&st);//销毁栈
    if(ret)//当栈为空,即结束了匹配
        return true;
    else//栈内有数据,就说明循环结束时,原字符串有单个左括号无法被匹配。
        return false;
    

}

225. Implementing stacks with queues

Ideas: The nature of the queue is: first in, first out; the nature of the stack is: last in, last out.

You can create two queues, first use one to store data, and when you want to take out data, you can move the first N -1 data to another queue, take out (and delete) data, and reciprocate, simulating the implementation of stack related functions.

Drawing:

Remove and return the top element of the stack:

take out 5

Clear the data in queue 1

Insert data:

At the beginning, you can choose an empty queue to insert at will, and the elements inserted later must be inserted into a non-empty queue.

Here, empty and non-empty queues can be established by a select statement.

Return the top element of the stack:

The queue has the function of accessing the elements at the end of the queue, so it can be implemented directly through the queue.

Check if it is empty:

When both queue 1 and queue 2 are empty at the same time, the stack is empty.

Code:

typedef int QDataType;

//链表的节点
typedef struct QueueNode
{
	QDataType data;//数据
	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, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head && pq->tail);

	if (pq->head->next == NULL)
	{
		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 && pq->tail == NULL;
	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;
}

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

	return pq->head->data;
}

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

	return pq->tail->data;
}

typedef struct {
    //创建两个队列
    Queue q1;
    Queue q2;

} MyStack;


MyStack* myStackCreate() {
    //为结构体分配空间,不能使用
    //MyStack st;  栈上开辟的临时变量,出栈即销毁,返回的指针为空指针。
    //在堆上开辟空间,malloc动态开辟
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    //assert(pst);//可有可无
    //Mystack结构体成员初始化
    QueueInit(&pst->q1);

    QueueInit(&pst->q2);
    return pst;
}

void myStackPush(MyStack* obj, int x) {
    //非空的队列放入数据,始终保持存在一个空的队列
    if(!QueueEmpty(&obj->q1))//非空
    {
        QueuePush(&obj->q1,x);
    }
    else
    {
        QueuePush(&obj->q2,x);
    }

}

int myStackPop(MyStack* obj) {
    //assert(obj);
    //指定一个空队列和非空队列,定义q1为空
    Queue* empty = &obj->q1;
    Queue* nonempty = &obj->q2;
    //若不是,就交换
    if(!QueueEmpty(&obj->q1))
    {
        empty = &obj->q2;
        nonempty = &obj->q1;
    }
    while(QueueSize(nonempty)>1)//从非空队列中持续取数据放入空队列中,并删数据
    {
        QDataType front = QueueFront(nonempty);//获取数据
        QueuePush(empty,front);//插入数据
        QueuePop(nonempty);//删数据
    }
    //获取“栈顶”数据
    QDataType top = QueueFront(nonempty);
    移除栈顶数据
    QueuePop(nonempty);
    //返回“栈顶”元素
    return top;

}

int myStackTop(MyStack* obj) {
    //指定一个空队列和非空队列,定义q1为空
    Queue* empty = &obj->q1;
    Queue* nonempty = &obj->q2;
    //若不是,就交换
    if(!QueueEmpty(&obj->q1))
    {
        empty = &obj->q2;
        nonempty = &obj->q1;
    }

    return QueueBack(nonempty);

}

bool myStackEmpty(MyStack* obj) {
    assert(obj);
    //当q1和q2同时为空时,“栈”为空
    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);

}

void myStackFree(MyStack* obj) {
    //释放内存时,先解决结构体内部的q1和q2
    assert(obj);
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
    //置空并不会改变实参的状态

}

Implementing queues with stacks

Ideas: The nature of the stack: last in, last out; the nature of the queue: first in, first out.

Create two stacks and simulate the basic functions of queues on the two stacks.

Drawing:

First-in 1  2  3  4  5  data

pop

Take out the head element 1

Migrate all elements of stack 1 to stack 2

Extract target element 1 from stack two

peek

It can be seen from pop that the data in stack 2 can imitate the data out of the queue.

From this, it can be concluded that the simulation implementation queue only needs to import the data once .

 

push

 

According to the existing conclusions, import the data into stack 1 first, and then import the data in stack 1 into stack 2 when the data in stack 2 is deleted .

 

empty

 The queue is empty when stack 1  and stack 2 are both empty.

 

Note: When pop and push data, it is necessary to judge whether it is empty.

 

Code:

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;
void StackInit(Stack* ps)
{
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

//销毁
void StackDestroy(Stack* ps)
{
	
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

//入栈
void StackPush(Stack* ps, STDataType x)
{
	//断言
	assert(ps);
	//判断是否需要扩容
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? ps->capacity = 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);
		//判断扩容是否成功
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	//插入数据
	//数组的下标从0开始,top指向的就是栈顶
	ps->a[ps->top] = x;
	ps->top++;
}

//出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//断言栈是否为空
	assert(ps->top > 0);

	ps->top--;
}

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
	//断言栈是否为空
	assert(ps->top);

	return ps->a[ps->top-1];
}

//检测栈是否为空
bool StackEmpty(Stack* ps)
{
	assert(ps);
	非空
	//if (ps->top > 0)
	//{
	//	return false;
	//}
	为空
	//else
	//	return true;
	//更优化的写法
	return ps->top == 0;
}

int StackSize(Stack* ps)
{
	assert(ps);
	//返回个数,top指的是栈顶数据的下一位。
	return ps->top;
}

typedef struct {
    Stack s1;//储存数据最初始的栈
    Stack s2;//取数据专用的栈

} MyQueue;
bool myQueueEmpty(MyQueue* obj);

MyQueue* myQueueCreate() {
    //分配空间
    MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
    //初始化
    StackInit(&obj->s1);//放数据
    StackInit(&obj->s2);
    return obj;
}

void myQueuePush(MyQueue* obj, int x) {
    //插入数据,s1为储存初始数据的栈
    StackPush(&obj->s1,x);
}

int myQueuePop(MyQueue* obj) {
    //如果s2为空
    if(StackEmpty(&obj->s2))
    {
        //导数据
        while(StackSize(&obj->s1))
    {
        int top = StackTop(&obj->s1);
        StackPush(&obj->s2,top);
        StackPop(&obj->s1);
    }
    }
    int top = StackTop(&obj->s2);
    StackPop(&obj->s2);
    return top;
}

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&obj->s2))
    {
    while(StackSize(&obj->s1))
    {
        int top = StackTop(&obj->s1);
        StackPush(&obj->s2,top);
        StackPop(&obj->s1);
    }
    }
    int top = StackTop(&obj->s2);
    return top;
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->s2) && StackEmpty(&obj->s1);
}

void myQueueFree(MyQueue* obj) {
    StackDestroy(&obj->s1);
    StackDestroy(&obj->s2);
    free(obj);
}

622. Designing Circular Queues

Ideas:

Create a structure variable, record the head and tail, k, an array of pointers.

Condition for judging empty: When head == tail, it means the queue is empty.

But the condition for the queue to be full is also head == tail.

solution:

Is empty

In order to be able to use the head == tail judgment

condition, which is generally considered to be full.

In order to ensure that the space must be able to store k elements, the array space +1 can be satisfied.

The condition for judging to be empty at this time: head == tail

  Judgment as full condition: head = tail + 1

Note: The extra space is random in the array, not at the end of the array.

Drawing:

The ring only stores 5 data, opening up 6 spaces

After a series of insert and delete operations:

reinsert value

At this point, 5 values ​​have been inserted , the queue is full, and the judgment condition becomes tail+1 == head

This is in the case of multiple inserts and deletes, if no delete operation is performed:

It's full now. Judgment condition tail == k

 

Code:

typedef struct {
    //数组,头,尾,k
    int* a;
    int head;
    int tail;
    int k;

} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
    //分配空间
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //结构体内部的数组也需要开辟空间,为方便找到循环结束条件多开一个单位
    obj->a = (int*)malloc(sizeof(int)*(k+1));
    //初始化
    obj->head = obj->tail = 0;
    obj->k = k;
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //判断循环队列是否已满
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    else
    {
        obj->a[obj->tail] = value;
        //更新tail
        //如果走到尾的话,就归0
        if(obj->tail == obj->k)
        {
            obj->tail = 0;
        }
        else
            obj->tail++;
    }
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        //更新头
        if(obj->head == obj->k)
        {
            obj->head = 0;
        }
        //数据覆盖即可
        else
            obj->head++;
        return true;
    }
    
}

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        if(obj->tail == 0)
        {
            return obj->a[obj->k];
        }
        else
            return obj->a[obj->tail-1];
    }

}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->head == obj->tail;
    
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->head==0 && obj->tail == obj->k)
    {
        return true;
    }
    else if(obj->tail+1 == obj->head)
    {
        return true;
    }
    else
        return false;

}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

Guess you like

Origin blog.csdn.net/weixin_61932507/article/details/123992536