栈与队列Oj题

1.栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫做出栈。出数据也在栈顶。 

栈一般用数组实现,因为数组在尾上插入数据的代价比较小,top一般指向尾元素的下一个。

2.队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)。

入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

 队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数 组头上出数据,效率会比较低。

OJ题目

 1.有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

解法:使用栈来解决,因为每次进去的右括号会与最早进去的左括号去试图匹配。因此左括号全部进栈,而右括号进去,若栈空,返回false,若栈顶不是相匹配的左括号,返回false。若正好匹配,则将该左括号出战即可。

#define INITSIZE 3
#define ADDSIZE 2

// 支持动态增长的栈
typedef char STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;
void StackInit(Stack* ps)
{
	ps->arr = (STDataType*)malloc(sizeof(STDataType) * INITSIZE);
	if (ps->arr == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	ps->top = 0;     //top指向栈顶的下一个元素
	ps->capacity = INITSIZE;
}
static void checkFull(Stack* ps)
{
	
	if (ps->top == ps->capacity)
	{
		STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * (ps->capacity + ADDSIZE));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(EXIT_FAILURE);
		}
		ps->arr = tmp;
		ps->capacity = ps->capacity + ADDSIZE;
	}
}
void StackPush(Stack* ps, STDataType data)
{
	checkFull(ps);
	assert(ps);
	ps->arr[ps->top] = data;
	ps->top++;
}

void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top >0);
	ps->top--;
}

STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);

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

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


int StackEmpty(Stack* ps)
{
	assert(ps);
	if (ps->top != 0)
	{
		return false;
	}
	return true;
}

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

bool isValid(char * s){
    Stack  st;
    StackInit(&st);
    char topval;
    while(*s)
    {
       switch(*s)
       {
           case '(':
           case '{':
           case '[':
                        StackPush(&st,*s);
							break;
            case ')':
				    if(StackEmpty(&st))
					{
						StackDestroy(&st);
						return false;
                    }
                if(StackTop(&st)=='(')
                    StackPop(&st);
                else 
					{
					    StackDestroy(&st);
					    return false;
					}
					break;
            case ']': 
					if(StackEmpty(&st))
					{
						StackDestroy(&st);									                    return false;
					}
               
            if(StackTop(&st)=='[')
                StackPop(&st);
            else 
            		{
						StackDestroy(&st);
						return false;
				    }
              
					break;
            case '}':
                if(StackEmpty(&st))
					{
					    StackDestroy(&st);
					    return false;
					}
                if(StackTop(&st)=='{')
                StackPop(&st);
                else 
					{
					    StackDestroy(&st);
						return false;
					}
                    break;
       }
        s++;
    }
    bool ret=StackEmpty(&st);
		StackDestroy(&st);
    return ret;
}

2.用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

解法:关键是push和pop操作,我们可以push时将它全部push到一个队列中,下次push依然push到该队列之中,然后需要pop时,先把前n-1个元素push到另一个队列中,再pop剩余那一个元素,再次pop时依然如此,将这些元素前n-1个元素移动到空队列,再pop剩余那一个。

typedef int QDataType;

// 链式结构:表示队列
typedef struct QListNode
{
	struct QListNode* _next;
	QDataType _data;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
	int size;
}Queue;
void QueueInit(Queue* q)
{
	assert(q);
	q->front = q->rear = NULL;
	q->size = 0;
}

void QueuePush(Queue* q, QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	newnode->_data = data;
	newnode->_next = NULL;
	if (q->front ==NULL)
	{
		q->front = q->rear = newnode;
	}
	else
	{
		q->rear->_next = newnode;
		q->rear = newnode;
	}
	q->size++;
}

void QueuePop(Queue* q)
{
	assert(q && q->front);
	QNode* next = q->front->_next;
	free(q->front);
	q->front = next;
	if (q->front == NULL)
		q->rear = NULL;
	q->size--;
}

QDataType QueueFront(Queue* q)
{
	assert(q&&q->front);
	return q->front->_data;
}

QDataType QueueBack(Queue* q)
{
	assert(q && q->front);
	return q->rear->_data;
}

int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

int QueueEmpty(Queue* q)
{
	assert(q);
	if (q->front == NULL)
	{
		return 1;
	}
	return 0;
}

void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->front;
	QNode* next;
	while (cur)
	{
		next = cur->_next;
		free(cur);
		cur = next;
	}
	q->front = q->rear = NULL;
	q->size = 0;
}


typedef struct {
  Queue q1;
  Queue q2;
} MyStack;


MyStack* myStackCreate() {
        MyStack *st=(MyStack*)malloc(sizeof(MyStack));
        QueueInit(&(st->q1));
        QueueInit(&(st->q2));
				return st;
}

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

int myStackPop(MyStack* obj) {
   
    QNode* cur = QueueEmpty(&obj->q1) ? obj->q2.front : obj->q1.front;
    QNode* tail = QueueEmpty(&obj->q1) ? obj->q2.rear : obj->q1.rear;
		//这里两个队列只有存放 队列地址传入进去才能改变q1,q2
    Queue *NullQueue = QueueEmpty(&obj->q1) ? &obj->q1 : &obj->q2;
    Queue *dataQueue = QueueEmpty(&obj->q1) ? &obj->q2 : &obj->q1;
    int  tmp = QueueBack(dataQueue);
    while (cur != tail)
    {
        cur = cur->_next;
        QueuePush(NullQueue, QueueFront(dataQueue));
        QueuePop(dataQueue); 
    }
    QueuePop(dataQueue);
    return tmp;

}

int myStackTop(MyStack* obj) {
    Queue *dataQueue = QueueEmpty(&obj->q1) ? &obj->q2 : &obj->q1;
    return QueueBack(dataQueue);
}

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    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);
*/

3.用栈实现队列 ​​​​​​x  

我们将两个栈分为一个pop栈,一个push栈,每次加入元素总是加入push栈中,删除元素总是在pop栈之中,当pop栈为空,那么将push栈元素全部给pop栈即可。

#define INITSIZE 3
#define ADDSIZE 2
// 支持动态增长的栈
typedef char STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;
void StackInit(Stack* ps)
{
	ps->arr = (STDataType*)malloc(sizeof(STDataType) * INITSIZE);
	if (ps->arr == NULL)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
	}
	ps->top = 0;     //top指向栈顶的下一个元素
	ps->capacity = INITSIZE;
}
static void checkFull(Stack* ps)
{
	
	if (ps->top == ps->capacity)
	{
		STDataType* tmp = (STDataType*)realloc(ps->arr, sizeof(STDataType) * (ps->capacity + ADDSIZE));
		if (tmp == NULL)
		{
			perror("realloc");
			exit(EXIT_FAILURE);
		}
		ps->arr = tmp;
		ps->capacity = ps->capacity + ADDSIZE;
	}
}
void StackPush(Stack* ps, STDataType data)
{
	checkFull(ps);
	assert(ps);
	ps->arr[ps->top] = data;
	ps->top++;
}

void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top >0);
	ps->top--;
}

STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);

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

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


int StackEmpty(Stack* ps)
{
	assert(ps);
	if (ps->top != 0)
	{
		return false;
	}
	return true;
}

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


typedef struct {
        Stack popstack;
        Stack pushstack;
} MyQueue;


MyQueue* myQueueCreate() {
        MyQueue* q=(MyQueue*)malloc(sizeof(MyQueue));
        StackInit(&q->popstack);
        StackInit(&q->pushstack);
				return q;
}

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

int myQueuePop(MyQueue* obj) {
	 int ret=0;
	 //pop栈为空,则将push栈数据全部给pop栈
	 if(StackEmpty(&obj->popstack))
			{
				while(!StackEmpty(&obj->pushstack))
				{
				 StackPush(&obj->popstack,StackTop(&obj->pushstack));
				 StackPop(&obj->pushstack);
				}
			}

		ret= StackTop(&obj->popstack);
    StackPop(&obj->popstack);
		return ret;
}

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

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

/**
 * 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);
*/

4.设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

解法:采用顺序表结构,因为这些空间是已经开辟好的(固定大小),同时rear指向的应该是当前插入元素的下一个(否则不好判断其是否为空),同时我们加入一个闲置位,便于我们判断循环链表是否已满。


// 循环队列已经开辟好了固定大小的空间,插入一个值,
//  rear往后走(类似栈)如果设计成链表,不好取出队列的尾元素 普通队列rear指向当前数据
typedef struct {
    int front;
    int rear;
    int capacity;
    int *elements;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue *obj = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));
    obj->capacity = k + 1;
    obj->rear = obj->front = 0;
    obj->elements = (int *)malloc(sizeof(int) * obj->capacity);
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if ((obj->rear + 1) % obj->capacity == obj->front) {
        return false;
    }
    obj->elements[obj->rear] = value;
    obj->rear = (obj->rear + 1) % obj->capacity;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if (obj->rear == obj->front) {
        return false;
    }
    obj->front = (obj->front + 1) % obj->capacity;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    if (obj->rear == obj->front) {
        return -1;
    }
    return obj->elements[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if (obj->rear == obj->front) {
        return -1;
    }
    return obj->elements[(obj->rear - 1 + obj->capacity) % obj->capacity];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->rear == obj->front;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear + 1) % obj->capacity == obj->front;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值