栈的简单认识和基本操作:点击打开链接
队列的简单认识和基本操作:点击打开链接
一.实现一个栈,要求实现Push(出栈),Pop(出栈),Min(返回最小值)的时间复杂度为O(1)。
(1.)方法一:创建两个栈来实现(Stack1,Stack2)
思路:
首先创建栈Stack1和Stack2时把两个栈放在一个结构体里这样可以更加方便操作
入栈:
1.如果Stack1和Stack2两个栈都为空则元素data入两个栈。
2.如果Stack2的栈顶元素(top)大于要插入元素data,则只入栈Stack1
3.如果Stack2d的栈顶元素(top)小于等于要插入元素data,则栈Stack1和栈Stack2都要插入。
出栈:
1.用上边方法实行入栈后则栈Stack2的栈顶(top)就是所要取的最小值
2.如果要进行出栈时则要比较如果Stack1和Stack2的栈顶(top)元素相同则同时出栈,如果两个栈的栈顶元素不同则只出Stack1的栈顶(top)
接下来看一下图解:
实现的代码:
queueandstack.h
#pragma once #include<stdio.h> #include<Windows.h> #include<assert.h> #define MAX_SIZE 100 typedef int DataType; typedef struct Stack1 { DataType array1[MAX_SIZE]; //里边放封装的结构体 int size; //元素个数 }Stack1; typedef struct Stack2 { DataType array2[MAX_SIZE]; int size; }Stack2; typedef struct Stack { Stack1 s1; Stack2 s2; }Stack; //初始化栈 void InitStack(Stack* s); //给栈顶插入元素 void StackPush(Stack* s, DataType data); //出栈 void StackPop(Stack* s); //栈顶元素 DataType StackTop(Stack* s); //返回栈最小元素 int StackMindata(Stack* s);
queueandstack.c
//初始化栈 void InitStack(Stack* s) { assert(s); s->s1.size = 0; s->s2.size = 0; } //给栈顶插入元素 void StackPush(Stack* s, DataType data) { assert(s); if (s->s1.size == MAX_SIZE && s->s2.size == MAX_SIZE) { printf("栈已满!!!"); return; } //如果两个栈都为空,则入两个栈 if (s->s1.size == 0 && s->s2.size == 0) { s->s1.array1[s->s1.size] = data; s->s2.array2[s->s2.size] = data; s->s1.size++; s->s2.size++; } //s2中的栈顶元素大于等于data则如两个栈 else if (StackTop(&(s->s2)) >= data) { s->s1.array1[s->s1.size] = data; s->s2.array2[s->s2.size] = data; s->s1.size++; s->s2.size++; } //data大于s2栈顶的元素则只入s1的栈 else { s->s1.array1[s->s1.size] = data; s->s1.size++; } } //出栈 void StackPop(Stack* s) { assert(s); if (s->s1.size == 0 && s->s2.size == 0) { printf("栈已空!!!"); return; } //如果两个栈中栈顶元素相同都出栈 if (s->s1.array1[s->s1.size] == StackTop(&(s->s2))) { s->s1.size--; s->s2.size--; } else { s->s1.size--; } } //返回栈最小元素 int StackMindata(Stack* s) { assert(s); if (s->s1.size == 0 && s->s2.size == 0) { printf("栈已空!!!"); return 0; } return (StackTop(&(s->s2))); } //栈顶元素 DataType StackTop(Stack2* s2) { assert(s2); if (s2->size == 0) { printf("栈已空!!!"); return 0; } return (s2->array2[s2->size - 1]); }
test.c
void QueueStackTest() { Stack s; InitStack(&s); StackPush(&s, 6); StackPush(&s, 5); StackPush(&s, 4); StackPush(&s, 3); printf("mindata: %d\n",StackMindata(&s)); StackPop(&s); printf("mindata: %d\n", StackMindata(&s)); } int main() { QueueStackTest(); system("pause"); return 0; }
方法二:使用一个栈,需要封装一个结构体
思路:
1.首先将要插入元素data和要求的最小元素MinData封装为一个结构体
2.入栈:
(1.)如果栈为空则直接插入(将封装的结构体中的data和Mindata都赋值为所要插的元素data)
(2.)如果栈不为空
A
.需要比较:MinData小于data则用栈顶的MinData更新MinData
B.比较MinData大于data则直接进栈(data和MinData都是所要插入元素data)
(3.)全部入栈后则栈顶的MinData就是最小值
3.出栈:只需要让栈中的元素个数减一(size--)
图解:
实现的代码:
queueandstack.h
#pragma once #include<stdio.h> #include<Windows.h> #include<assert.h> #define MAX_SIZE 100 typedef int DataType; typedef struct NewData { DataType data; //将data和MinData封装一个结构体 DataType MinData; }NewData; typedef struct Stack { NewData array[MAX_SIZE]; //里边放封装的结构体 int size; //元素个数 }Stack; //初始化栈 void InitStack(Stack* s); //给栈顶插入元素 void StackPush(Stack* s, DataType data); //出栈 void StackPop(Stack* s); //返回栈最小元素 int StackMindata(Stack* s);
queueandstack.c
//初始化栈 void InitStack(Stack* s) { assert(s); s->size = 0; } //给栈顶插入元素 void StackPush(Stack* s, DataType data) { assert(s); if (MAX_SIZE == s->size) { printf("栈已满!!!"); return; } //栈里边没有数据的话直接进栈 if (s->size == 0) { s->array->data = s->array->MinData = data; s->size++; } //栈里边有数据且MinData小于data则用栈顶的MinData更新MinData else if ((s->array + s->size - 1)->MinData < data) { (s->array + s->size)->MinData = (s->array + s->size - 1)->MinData; (s->array + s->size)->data = data; s->size++; } //栈里边有数据且MinData大于则直接进栈 else { (s->array + s->size)->MinData = (s->array + s->size)->data = data; s->size++; } } //出栈 void StackPop(Stack* s) { assert(s); if (NULL == s->size) { printf("栈已空!!!"); return; } s->size--; } //返回栈最小元素 int StackMindata(Stack* s) { assert(s); if (NULL == s->size) { printf("栈已空!!!"); return; } return ((s->array + s->size - 1)->MinData); }
test.c
void QueueStackTest() { Stack s; InitStack(&s); StackPush(&s, 4); StackPush(&s, 5); StackPush(&s, 3); StackPush(&s, 1); printf("mindata: %d\n",StackMindata(&s)); StackPop(&s); printf("mindata: %d\n", StackMindata(&s)); } int main() { QueueStackTest(); system("pause"); return 0; }
二. 使用两个栈(Stack1和Stack2)实现一个队列(队列的特点:先进先出)
实现方法:在Stack1和Stack2中如果Stack1中的元素个数超过1且Stack2中的元素个数为空则必须把Stack1中的元素导入Stack2中直到Stack1中只有一个元素再输出Stack1中的元素。如此往复每次判断任意一个栈为空在把另外一个元素个数不为一的栈中的元素导入令外一个栈直到元素个数不为一的栈中只剩一个元素然后输出这个元素。如此往复知道将插入的元素全部输出就实现了队列 。
图解:
实现代码:
queueandstack.h
#pragma once #include<stdio.h> #include<Windows.h> #include<assert.h> #define MAX_SIZE 100 typedef int DataType; typedef struct Stack { DataType array[MAX_SIZE]; //里边放封装的结构体 int size; //元素个数 }Stack; typedef struct Queue { Stack s1; Stack s2; }Queue; //初始化栈 void InitStack(Queue* q); //给栈顶插入元素 void StackPush(Stack* s, DataType data); //出栈 void StackPop(Stack* s); //队顶元素 DataType QueueTop(Stack* s); //栈顶元素 DataType StackTop(Stack* s); //入队列 void QueuePush(Queue* q); //出队列 void QueuePop(Queue* q); //获取队头元素 DataType QueueFront(Queue* q); //获取队尾元素 DataType QueueTail(Queue* q); //获取队列的元素个数 int QueueSize(Queue* q);
queueandstack.c
//初始化栈 void InitStack(Queue* q) { assert(q); q->s2.size = 0; q->s1.size = 0; } //用两个栈实现队列 void StackPush(Stack* s ,DataType data) { assert(s); if (MAX_SIZE == s->size) { printf("栈已满!!!\n"); return; } s->array[s->size] = data; s->size++; } //出栈 void StackPop(Stack* s) { assert(s); if (NULL == s->size) { printf("栈以空!!!\n"); return; } s->size--; } //栈顶元素 DataType StackTop(Stack* s) { assert(s); if (NULL == s->size) { printf("栈以空!!!\n"); return; } return (s->array[s->size - 1]); } //入队列 void QueuePush(Queue* q, DataType data) { assert(q); if (q->s1.size == MAX_SIZE) { //只有栈s2中为空时才能将s1的栈顶元素插入栈s2中,否则会找不到队头和队尾 if (NULL == q->s2.size) { while (q->s1.size != 0) { //先将栈s1中的栈顶保存起来 data = StackTop(&(q->s1)); //把s1的栈顶元素出栈 StackPop(&(q->s1)); //把data插入栈s2中 StackPush(&(q->s2), data); } } else return; } StackPush(&(q->s1),data); } //出队列 void QueuePop(Queue* q,DataType data) { assert(q); //如果栈s2中不为空则直接出栈 if (q->s2.size != 0) { StackPop(&(q->s2)); return; } else { //如果s1中也为空则直接出来 if (q->s1.size == 0) return; // else { while (q->s1.size != 0) { data = StackTop(&(q->s1)); StackPop(&(q->s1)); StackPush(&(q->s2), data); } StackPop(&(q->s2)); } } } //获取队头元素 DataType QueueFront(Queue* q) { assert(q); //判断两个栈中是否都有元素 if (q->s1.size == 0 && q->s2.size == 0) { printf("队列已空!!!\n"); return 0; } //如果s2中有元素则直接输出s2的栈顶就是队列的队头 else if (q->s2.size != 0) { return StackTop(&(q->s2)); } //如果s2为空则输出s1的栈底为队列的队头 else { return (q->s1.array[0]); } } //获取队尾元素 DataType QueueTail(Queue* q) { assert(q); //判断两个栈中是否都有元素 if (q->s1.size == 0 && q->s2.size == 0) { printf("队列已空!!!\n"); return 0; } //如果s2不为空并且s1中为空则输出s2栈底元素为队列的队尾 else if (q->s2.size != 0 &&q->s1.size == 0) { return (q->s2.array[0]); } //如果s2为空,s1不为空 和两个都不为空则直接输出s1的栈顶为队列的队尾 else { return StackTop(&(q->s1)); } } //获取队列的元素个数 int QueueSize(Queue* q) { assert(q); //判断两个栈中是否都有元素 if (q->s1.size == 0 && q->s2.size == 0) { printf("队列已空!!!\n"); return 0; } return(q->s1.array[q->s1.size] + q->s2.array[q->s2.size] - 1); }
test.c
void QueueStackTest() { Stack s; Queue q; InitStack(&q); QueuePush(&q, 5); QueuePush(&q, 4); QueuePush(&q, 1); QueuePush(&q, 3); printf("Front:%d\n", QueueFront(&q)); QueuePop(&q); //获取队头元素 printf("Front:%d\n", QueueFront(&q)); //获取队尾元素 printf("Tail:%d\n", QueueTail(&q)); QueuePush(&q, 1); QueuePush(&q, 2); QueuePop(&q); printf("Front:%d\n", QueueFront(&q)); printf("Tail:%d\n", QueueTail(&q)); printf("Size: %d\n", QueueSize(&q)); } int main() { QueueStackTest(); system("pause"); return 0; }