初阶数据结构 — 栈和队列

一. 栈

1. 什么是栈

        一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。 栈中的数据元素遵守 后进先出LIFO Last In First Out )的原则
         初阶数据结构 — 栈和队列_第1张图片

 2. 代码模拟栈

        2.1 stack.h 和 stack.c

//---------------------------stack.h-------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int capacity;
	int top;
}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);





//---------------------------stack.c-------------------------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"




static void Check_Capacity(ST* ps)
{
	assert(ps);

	if (ps->capacity  == ps->top)
	{
		int newncapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;

		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newncapacity);
		if (NULL == tmp)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->capacity = newncapacity;
		ps->a = tmp;

		//printf("realloc success\n");
	}
}


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);
	Check_Capacity(ps);
	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;
}

        2.2 test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"

void stack_test1() 
{
	ST stack;
	StackInit(&stack);

	StackPush(&stack, 1);
	StackPush(&stack, 2);
	StackPush(&stack, 3);
	StackPush(&stack, 4);
	StackPush(&stack, 5);
	StackPush(&stack, 6);
	StackPush(&stack, 7);
	StackPush(&stack, 8);
	//StackPush(&stack, 9);
	

	while (!StackEmpty(&stack))
	{
		printf("%d ", StackTop(&stack));
		StackPop(&stack);
	}
	
	printf("\nsize = %d", stack.top);
	printf("\ncapacity = %d", stack.capacity);
}



int main()
{
	stack_test1();

	return 0;
}

二 . 队列

1.什么是队列

        队列:只允许在 一端进行插入数据操作 在另一端进行删除数据操作的特殊线性表 ,队列具有先进先出 FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为 队头
初阶数据结构 — 栈和队列_第2张图片

  2. 代码模拟 队列

        2.1 queue.h 和 test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include

typedef int  QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;


typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

void QueueInit(Queue* pq);

void QueueDestroy(Queue* pq);

void QueuePush(Queue* pq,QDataType x);

void QueuePop(Queue* pq);

QDataType QueueFront(Queue* pq);

QDataType QueueBack(Queue* pq);

bool QueueEmpty(Queue* pq);

int QueueSize(Queue* pq);



//-------------------test.c----------------------
#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"
Qtest1()
{
	Queue q;
	QueueInit(&q);

	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);

	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	
	
	printf("\n");
	
}

int main()
{
	Qtest1(); 

	return 0;
}

        2.2 queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"


void QueueInit(Queue* pq)
{

	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;

}
void QueueDestroy(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));
	if (NULL == newnode)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;

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

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->head->next == NULL)
	{//1. 只有一个结点
		free(pq->head);
		pq->head = pq->tail = NULL;
		pq->size--;
	}
	else
	{//2. 多个结点
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
		pq->size--;
	}
	
}


QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{

	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
	
}

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

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

三. 栈和队列相关题目【力扣】

1. 用队列实现栈  —— 栈 | 后进先出

        队列实现栈的基本思想就是,用 个队列来实现栈,当第一次入栈时,从队列 1 中入队,出栈时,需要把队列 1 中的 n - 1个数据倒入到队列 2 中,然后将队列 1 中仅剩的最后一个数据出掉,这个就是出栈动作,当要在继续入栈时,需要入到有元素(队列 2)的栈,然后再次需要出栈时,以此往复,此过程中,始终有一个队列为空,入栈只入非空的队列

#include
#include
#include
#include


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);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);


// 初始化队列 
void QueueInit(Queue* q)
{
    assert(q);
	q->size = 0;
	q->_front = q->_rear = NULL;
}

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
    assert(q);
	QNode* tmp = (QNode*)malloc(sizeof(QNode));
	if (NULL == tmp)
	{
		perror("Push mfail");
		exit(-1);
	}
    tmp->_data = data;
    tmp->_next = NULL;
	
	if (q->_rear == NULL)
	{
		q->_front = q->_rear = tmp;
	}
	else
	{
		q->_rear->_next = tmp;
        q->_rear = tmp;

	}
	q->size++;
}

// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
    if(q->_front->_next == NULL)
    {
        free(q->_front);
        q->_front = q->_rear = NULL;
    }
    else
    {
        QNode* hnext = q->_front->_next;
	    free(q->_front);
	    q->_front = hnext;
    }
	q->size--;
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);
	return q->_front->_data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);
	return q->_rear->_data;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q)
{
    assert(q);
	return q->_front == NULL;
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);
	//assert(!QueueEmpty(q));
	QNode* cur = q->_front;
	while (cur)
	{
		QNode* 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) {

    Queue* Nempty = &obj->q1;
    Queue* Empty = &obj->q2;
    
    if(QueueEmpty(&obj->q1))//判定非空队列
    {
        Nempty = &obj->q2;
        Empty = &obj->q1;
    }

    while(QueueSize(Nempty) > 1)
    {
        QueuePush(Empty, QueueFront(Nempty));
        QueuePop(Nempty);
    }
    
    int ret = QueueFront(Nempty);
    QueuePop(Nempty);
    return ret;
}


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

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

2.用栈实现队列 —— 队列 | 后进后出

        用栈实现队列的基本实现,用 2 个栈来实现队列,一个栈负责队列,另一个栈负责队列,当进元素时push栈负责接收元素,当需要pop元素时,则直接将pop栈中的元素依次pop出队列,当pop栈没有元素时,需要先将push栈的所有元素倒入到pop栈时。

#include
#include
#include
#include

typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps); 
// 入栈 
void StackPush(Stack* ps, STDataType data); 
// 出栈 
void StackPop(Stack* ps); 
// 获取栈顶元素 
STDataType StackTop(Stack* ps); 
// 获取栈中有效元素个数 
int StackSize(Stack* ps); 
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps); 
// 销毁栈 
void StackDestroy(Stack* ps); 

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;//top是0,top指向的是栈顶元素的下一个位置。
}


// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	if (ps->_capacity == ps->_top)
	{
		int newcapacity = ps->_capacity == 0 ? 2 : ps->_capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);
		if (NULL == tmp)
		{
			perror("realloc fail");
			exit(-1);
		}

		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}
	ps->_a[(ps->_top)++] = data;
}

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);//为空不能删了
	--(ps->_top);
}

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	return ps->_a[(ps->_top - 1)];
}

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->_top;
}

// 判断栈是否为空
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->_top == 0;
}

// 销毁栈 
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------/
typedef struct {
    Stack st1;//入
    Stack st2;//出
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* tmp = (MyQueue*)malloc(sizeof(MyQueue));
    StackInit(&tmp->st1);
    StackInit(&tmp->st2);
    
    return tmp;
}

void myQueuePush(MyQueue* obj, int x) {

    assert(obj);
    StackPush(&obj->st1,x);

}

int myQueuePop(MyQueue* obj) {
    assert(obj);
    if(!StackEmpty(&obj->st2))//负责出的栈有数据就直接出
    {
        int ret = StackTop(&obj->st2);
        StackPop(&obj->st2);
        return ret;
    }
    else //没数据就要先把队列1的全部倒进来
    {
        while(StackSize(&obj->st1) > 0)
        {
            StackPush(&obj->st2,StackTop(&obj->st1));
            StackPop(&obj->st1);
        }
        int ret = StackTop(&obj->st2);
        StackPop(&obj->st2);
        return ret;
    }

}

int myQueuePeek(MyQueue* obj) {
    assert(obj);

    if(!StackEmpty(&obj->st2))//负责出的栈有数据就直接出
    {
        int ret = StackTop(&obj->st2);
        return ret;
    }
    else //没数据就要先把队列1的全部倒进来
    {
        while(StackSize(&obj->st1) > 0)
        {
            StackPush(&obj->st2,StackTop(&obj->st1));
            StackPop(&obj->st1);
        }
        int ret = StackTop(&obj->st2);
        return ret;
    }
}

bool myQueueEmpty(MyQueue* obj) {
    assert(obj);

    return StackEmpty(&obj->st1) && StackEmpty(&obj->st2);
}

void myQueueFree(MyQueue* obj) {
    assert(obj);

    StackDestroy(&obj->st1);
    StackDestroy(&obj->st2);
    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);
*/

3. 设计循环队列  —— 数组实现 

        这里直接上图解和代码

初阶数据结构 — 栈和队列_第3张图片

typedef struct {
    int front;
    int tail;
    int size;
    int *arr;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
   
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(NULL == obj)
    {
        perror("Cir mfail");
        exit(-1);
    }
    int* tmp = (int*)malloc(sizeof(int) * (k + 1));
    if(NULL == tmp)
    {
        perror("Cir mfail");
        exit(-1);
    }
    obj->arr = tmp;
    obj->front = obj->tail = 0;
    obj->size = k;
    return obj;
}

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

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

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    
    obj->arr[obj->tail] = value;
    obj->tail++;
    obj->tail %=(obj->size + 1);
    
    return true;
}

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

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

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
        return obj->arr[(obj->tail + obj->size)%(obj->size + 1)];
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    obj->front = obj->tail = obj->size = 0;
    free(obj);
}

你可能感兴趣的:(初级数据结构,数据结构,c语言)