[Structure de données] Exemple classique de pile et de file d'attente - C pur

 s​​​​​​​20. Parenthèses valides

L'utilisation de la pile pour résoudre le problème décrit par le titre est la solution optimale.

Idées : 1) Trouvez les parenthèses de gauche, placez-les sur la pile et commencez à faire éclater la pile lorsque vous rencontrez la parenthèse de droite. Si les critères de correspondance ne sont pas remplis, renvoyez false

2) Pendant le processus de correspondance, les données de la pile sont vides mais les données doivent être extraites de la station. Une fois le parcours de la chaîne terminé, les données de la pile ne sont pas vides, ce qui nécessite une attention supplémentaire.

Dessin:

Traitement supplémentaire pour l'idée 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. Implémenter des piles avec des files d'attente

Idées : La nature de la file d'attente est : premier entré, premier sorti ; la nature de la pile est : dernier entré, dernier sorti.

Vous pouvez créer deux files d'attente, en utiliser d'abord une pour stocker des données, et lorsque vous souhaitez extraire des données, vous pouvez déplacer les premières données N -1 vers une autre file d'attente, extraire (et supprimer) des données et inverser pour simuler les fonctions associées. de la pile.

Dessin:

Supprimez et retournez l'élément supérieur de la pile :

sortir 5

Effacer les données de la file d'attente 1

Insérer des données :

Au début, vous pouvez choisir une file vide à insérer à volonté, et les éléments insérés plus tard doivent être insérés dans une file non vide.

Ici, des files d'attente vides et non vides peuvent être établies par une instruction select.

Renvoie l'élément supérieur de la pile :

La file d'attente a pour fonction d'accéder aux éléments à la fin de la file d'attente, elle peut donc être mise en œuvre directement via la file d'attente.

Vérifiez s'il est vide :

Lorsque les files d'attente 1 et 2 sont vides en même temps, la pile est vide.

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);
    //置空并不会改变实参的状态

}

Implémenter des files d'attente avec des piles

Idées : La nature de la pile : dernier entré, dernier sorti ; la nature de la file d'attente : premier entré, premier sorti.

Créez deux piles et simulez les fonctions de base des files d'attente sur les deux piles.

Dessin:

Premières  données 1  2  3  4  5

pop

Retirez l'élément de tête 1

Migrer tous les éléments de la pile 1 vers la pile 2

Extraire l'élément cible 1 de la pile deux

peek

On peut voir sur pop que les données de la pile 2 peuvent imiter les données hors de la file d'attente.

À partir de là, on peut en conclure que la file d'attente de mise en œuvre de la simulation n'a besoin d'importer les données qu'une seule fois .

 

push

 

Selon les conclusions existantes, importez d'abord les données dans la pile 1 , puis importez les données de la pile 1 dans la pile 2 lorsque les données de la pile 2 sont supprimées .

 

empty

 La file d'attente est vide lorsque la pile 1  et la pile 2 sont toutes deux vides.

 

Remarque : Lorsque vous pop et push des données, il est nécessaire de juger si elles sont vides.

 

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. Concevoir des files d'attente circulaires

Idées :

Créez une variable de structure, enregistrez la tête et la queue, k, un tableau de pointeurs.

Condition pour juger vide : Lorsque head == tail, cela signifie que la file d'attente est vide.

Mais la condition pour que la file d'attente soit pleine est aussi head == tail.

Solution:

Est vide

Afin de pouvoir utiliser le jugement tête == queue

état, qui est généralement considéré comme plein.

Afin de s'assurer que l'espace doit pouvoir stocker k éléments, l'espace tableau +1 peut être satisfait.

La condition pour juger d'être vide à ce moment : head == tail

  Jugement en pleine condition : tête = queue + 1

Remarque : L'espace supplémentaire est aléatoire dans le tableau, pas à la fin du tableau.

Dessin:

L' anneau ne stocke que 5 données, ouvrant 6 espaces

Après une série d'opérations d'insertion et de suppression :

réinsérer la valeur

À ce stade, 5 valeurs ont été insérées , la file d'attente est pleine et la condition de jugement devient queue + 1 == tête

C'est dans le cas d'insertions et de suppressions multiples, si aucune opération de suppression n'est effectuée :

C'est plein maintenant. Condition de jugement queue == 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);
}

Acho que você gosta

Origin blog.csdn.net/weixin_61932507/article/details/123992536
Recomendado
Clasificación