1. 利用顺序栈判断一个字符串是否为对称串。
- 算法思想:对于字符串str,从头到尾将其所有元素连续进栈,如果所有元素连续出栈产生的序列和str从头到尾的字符依次相同,表示str是一个对称串,返回真;否则表示str不是对称串,返回假
bool Symmtry(ElemType str[]) //判断str是否为对称串
{
int i;
ElemType e;
SqStack* st; //定义顺序栈指针
InitStack(st); //初始化栈
for (i = 0; str[i] != '\0'; i++)
{
Push(st, str[i]); //将str的所有元素进栈
}
for (i = 0; str[i] != '\0'; i++) //处理str的所有字符
{
Pop(st, e); //返回退栈元素e
if (str[i] != e) //若e与当前字符串不同表示不是对称串
{
DestoryStack(st); //销毁栈
return false; //返回假
}
}
DestoryStack(st); //销毁栈
return true; //返回真
}
int main() //主函数
{
ElemType str[MaxSize] = { "reviver" };
cout << boolalpha << "字符串是对称串吗?—" << Symmtry(str)<<endl;
return 0;
}
如果使用链栈:
- 算法思想:让链表前一半元素依次进栈,当n为偶数时,前一半和后一半的个数相同;当n为奇数时,链表中心结点字符不必比较,移动链表指针到下一字符开始比较。
bool Judge(LinkList L, int n)
{
int i = 0;
LNode* p = L->next;
char a[n/2]; //a字符栈
for (i = 0; i < n / 2; i++) //链表前一半元素进栈
{
a[i] = p->data;
p = p->next;
}
i = i - 1;
if (n % 2 == 1) p = p->next; //若n是奇数,后移过中心结点
for(i;i>0;i--)
{
if (p->data == a[i]) p = p->next;
else return false;
}
if (i == -1) return false; //栈为空栈
return true;
}
程序分析:
- 运行结果
2. 假设以I和O分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,可以操作的序列称为合法序列,否则称为非法序列。判定所给的操作序列是否合法,若合法,返回true、否则返回 false(假定被判定的操作序列已存入一维数组中)。
算法思想:入栈后,栈内元素个数加1;出栈后,栈内元素个数减1,因此可将判定一组出入栈序列是否合法转化为一组由+1、-1组成的序列,它的任意前缀子序列的累加和不小于0(每次出或入栈操作后判断)则合法,否则非法。当入栈出栈操作全部结束后,最后判断栈的终态是否为空。
bool Judge(char str[])
{
int i = 0, j = 0;
while (str[j] != '\0')
{
switch (str[j])
{
case 'I':i++; break;
case 'O':i--;
if (i < 0) return false;
}
j++;
}
if (i == 0) return true;
else return false;
}
程序分析:
- 运行结果
3. 设有两个栈s1、s2都采用顺序栈方式,并共享一个存储区[0,…, maxsize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向、迎面增长的存储方式。试设计s1、s2有关入栈和出栈的操作算法。
- 算法思想:栈顶相向、迎面增长的存储方式即共享栈。
#include<stdio.h>
#define maxsize 10
typedef int ElemType;
typedef struct
{
ElemType data[maxsize];
int top[2];
}PStack;
void InitStack(PStack &s)
{
s.top[0] = -1;
s.top[1] = maxsize;
}
int push(PStack& s, int i, ElemType stacknum)
{
if (i < 0 || i>1)
{
printf("栈号输入不对!");
exit(0);
}
if (s.top[1] - s.top[0] == 1)
{
printf("栈已满\n");
return 0;
}
switch (i)
{
case 0:
{
s.data[++s.top[0]] = stacknum;
return 1;
break;
}
case 1:
{
s.data[--s.top[1]] = stacknum;
return 1;
}
}
}
ElemType pop(PStack& s, int i)
{
if (i < 0 || i>1)
{
printf("栈号输入不对!");
exit(0);
}
switch (i)
{
case 0:
{
if (s.top[0] == -1)
{
printf("栈空\n");
return -1;
}
else return s.data[s.top[0]--];
}
case 1:
{
if (s.top[1] == maxsize)
{
printf("栈空\n");
return -1;
}
else return s.data[s.top[1]++];
}
}
}
bool DispStack(PStack s, int stacknum)
{
int i;
if (s.top[0] == -1 && s.top[1] == maxsize)
{
printf("栈为空\n");
return false;
}
if(stacknum==0)
{printf("栈0中的元素为:");
for (i = 0; i <=s.top[0]; i++)
printf("%d ", s.data[i]);
printf("\n");
printf("栈顶元素为:%d\n", s.data[s.top[0]]);
}
else if (stacknum==1)
{
printf("栈1中的元素为:");
for (i = maxsize - 1; i >= s.top[1]; i--)
printf("%d ", s.data[i]);
printf("\n");
printf("栈顶元素为:%d\n", s.data[s.top[1]]);
}
}
void Input(PStack &s)
{
int symbol = 1, stacknum;
ElemType num;
while(symbol)
{
printf("输入0(0号栈)或1(1号栈),或3(退出):\n");
scanf("%d", &num);
if (num == 3) break;
else if (num < 0 || num>1)
{
printf("输入错误!\n");
break;
}
if (num==0||num==1)
{
printf("请输入元素值:\n");
scanf("%d", &stacknum);
if (push(s, num, stacknum) == 0)
{
printf("栈已满,无法添加!\n");
break;
}
}
}
}
int main()
{
PStack s;
InitStack(s);
Input(s);
DispStack(s, 0);
DispStack(s, 1);
printf("共享栈中当前有:%d个元素", maxsize - (s.top[1] - s.top[0]) + 1);
return 0;
}
程序分析:
- exit(0):正常运行程序并退出程序; exit(1):非正常运行导致退出程序;
- return():返回函数,若在主函数中,则会退出函数并返回一值。
- return返回函数值,是关键字; exit 是一个函数。
return 0是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。- return是函数的退出(返回);exit是进程的退出。 return是C语言提供的,exit是操作系统提供的(或者函数库中给出的)。
- return用于结束一个函数的执行,将函数的执行信息传出个其他调用函数使用;exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS(操作系统),这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是0 为正常退出,非0 为非正常退出。
- 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。
- 运行结果:
4. 对于环形队列来说,如果知道队头指针和队列中的元素个数,则可以计算队尾指针。也就是说,可以用队列中的元素个数代替队尾指针。设计出这种环形队列的初始化、进队、出队和判队空算法。
- 算法思想:当已知队列的队头指针front和队列中的元素个数count后,队尾指针rear的计算公式是rear=(front+ count)%MaxSize。因此,这种队列的队空条件为
count==0
;队满条件为count==Maxsize
;元素e的进队操作是先根据队头指针和元素个数求出队尾指针rear,将rear循环增1,然后将元素e放置在rear处;出队操作是先将队头指针循环增1,然后取出该位置的元素。
#include<iostream>
using namespace std;
#include<malloc.h>
#define MaxSize 10
typedef int ElemType;
typedef struct SqQueue
{
ElemType data[MaxSize];
int front;
int count;
};
void InitQueue(SqQueue*& q) //初始化算法
{
q = (SqQueue*)malloc(sizeof(SqQueue)); //分配空间
q->count = 0; //队列中的元素个数设置为0
q->front = 0; //队头指针设置为0
}
bool EmptyQueue(SqQueue *q) //判队空算法
{
return q->count==0;
}
bool enQueue(SqQueue*& q,ElemType e) //进队算法
{
int rear; //临时存放队尾指针
if (q->count == MaxSize) return false; //队满上溢出
else
{
rear = (q->front + q->count) % MaxSize;
q->data[rear] = e;
rear = (rear + 1) % MaxSize;
q->count++; //元素个数增1
return true;
}
}
bool deQueue(SqQueue*& q, ElemType &e) //出队算法
{
if (q->count == 0) return false; //队空下溢出
else
{
e = q->data[q->front];
q->count--; //元素个数减1
q->front = (q->front + 1) % MaxSize; //队头循环增1
return true;
}
}
int main()
{
SqQueue *q;
InitQueue(q);
cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl;
int i;
for (i = 0; i < MaxSize * 2; i = i + 2) enQueue(q, i);
cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl;
ElemType num;
for (i = 0; i < MaxSize; i++)
{
deQueue(q, num);
cout << num << ' ';
}
return 0;
}
程序分析:
- 运行结果
5. 采用一个不带头结点,只有一个尾结点指针rear的循环单链表存储队列,设计队列的初始化、进队、出队和判队空算法。
#include<iostream>
using namespace std;
#include<malloc.h>
typedef int ElemType;
typedef struct LinkNode
{
ElemType data;
struct LinkNode* next;
};
typedef struct LinkQueue
{
struct LinkNode* rear;
};
void InitQueue(LinkQueue& q) //初始化算法
{
q.rear = NULL;
}
bool EmptyQueue(LinkQueue q) //判队空算法
{
return q.rear == NULL;
}
void enQueue(LinkQueue& q, ElemType e) //进队算法
{
LinkNode* p;
p = (LinkNode*)malloc(sizeof(LinkNode)); //创建新结点
p->data = e;
if (q.rear == NULL) //原链队为空
{
p->next = p; //改为循环链表
q.rear = p; //rear指向新结点
}
else //原链队不空
{
p->next = q.rear->next; //将p结点插入到rear结点之后
q.rear->next = p; //改为循环链表
q.rear = p; //rear指向新结点
}
}
bool deQueue(LinkQueue& q, ElemType& e) //出队算法
{
LinkNode* p;
if (q.rear == NULL) return false; //队空
else if (q.rear->next == q.rear) //原队中只有一个结点
{
e = q.rear->data;
free(q.rear);
q.rear = NULL;
}
else //原队中有两个或两个以上的结点
{
p = q.rear->next; //p指向队头结点
e = p->data;
q.rear->next = p->next; //删除p结点
free(p); //释放结点空间
}
return true;
}
int main()
{
LinkQueue q;
InitQueue(q);
cout << boolalpha << "链队为空吗?—" << EmptyQueue(q) << endl;
int i;
for (i = 0; i < 20; i = i + 2) enQueue(q, i);
cout << boolalpha << "链队为空吗?—" << EmptyQueue(q) << endl;
ElemType num;
for (i = 0; i < 10; i++)
{
deQueue(q, num);
cout << num << ' ';
}
return 0;
}
程序分析:
- 运行结果:
6. Q是一个队列,S是一个空栈,实现将队列中的元素逆置。
#include<iostream>
using namespace std;
#include<malloc.h>
#define MaxSize 10
typedef int ElemType;
typedef struct Stack
{
ElemType data[MaxSize];
int top;
};
typedef struct Queue
{
ElemType data[MaxSize];
int front, rear;
int count; //记录队列中元素的个数
};
void InitStack(Stack& s)
{ s.top = -1; }
void InitQueue(Queue& q)
{
q.front = q.rear = 0;
q.count = 0;
}
bool Push(Stack& s, ElemType e)
{
if (s.top == MaxSize - 1) return false;
else
{
s.data[++s.top] = e;
return true;
}
}
bool enQueue(Queue& q, ElemType e)
{
if (q.count==MaxSize) return false;
else q.data[q.rear++] = e;
q.count++;
return true;
}
bool Pop(Stack& s, ElemType& e)
{
if (s.top == -1) return false;
else e = s.data[s.top--];
return true;
}
bool deQueue(Queue& q, ElemType& e)
{
if (q.count==0) return false;
else e = q.data[q.front++];
q.count--;
return true;
}
bool EmptyStack(Stack s)
{ return s.top == -1; }
bool EmptyQueue(Queue q)
{ return q.front == q.rear; }
int main()
{
Stack s;
InitStack(s);
cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //初始化,此时栈中没有元素
Queue q;
InitQueue(q);
cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl; //初始化,此时队列中没有元素
int i;
ElemType num;
for (i = 1; i <= MaxSize; i++)
{
enQueue(q, i); //元素入队
deQueue(q, num); //元素出队
cout << num<<' '; //输出出队元素
Push(s, num); //将出队元素入栈
}
cout << "\n";
cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //此时队列中的元素全部入栈,队列为空
q.rear = q.front = 0; //将front、rear再次置为0
for (i = 1; i <= MaxSize; i++)
{
Pop(s, num); //元素出栈
enQueue(q, num); //元素重新入队
deQueue(q, num); //元素重新出队
cout << num << ' ';
}
cout << "\n";
cout << boolalpha << "栈为空吗?—" << EmptyStack(s) << endl; //此时栈中元素全部入队,栈为空
cout << boolalpha << "队列为空吗?—" << EmptyQueue(q) << endl; //队列为空
return 0;
}
程序分析:
- !注意: 程序第86行要将front、rear重新置0。因为有一个元素入队,rear会加1;有一个元素出队,front会减1。而队列中的元素个数依靠count来统计,此时与front、rear无关。当第一轮元素入队、出队结束后,front、rear均为10。因此第二轮元素需要入队、出队时,首先要把front、rear置为0!!!
- 运行结果:
7. 设从键盘输入一序列的字符 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an。若 a i a_i ai为数字字符, a i a_i ai进队;若 a i a_i ai为小写字母,将队首元素出队,若 a i a_i ai为其他字符,表示输入结束。
- 算法思想:先建立一个环形队列,用while循环接收用户的输入,根据题目的要求,队列中只可能出现数字字符。
void fun()
{
ElemType a, e;
SqQuene *q;
InitQueue(q);
while (true)
{
printf("输入a:");
scanf("%s", &a);
if (a >= '0' && a <= '9')
{
if (!enQuene(q, a)) printf("队列满,不能进队\n");
}
else if (a >= 'a' && a <= 'z')
{
if (!deQueue(q, e)) printf("队列空,不能出队\n");
else printf("出队元素:%c\n", e);
}
else break;
}
DestoryQueue(q);
}
程序分析:
- !注意:程序第九行%s。
- 运行结果:
8. 将一个环形队列(容量为m,元素下标从0到n-1)的元素倒置。
- 算法思想:使用一个临时栈s,先将q队列中的所有元素出队并将其进桟栈s,直到队列空为止。然后初始化队列q(队列清空),再出栈s的所有元素并将其进队q最后销毁栈s。
- 与第六题类似!
void fun(SqQueue *&q,SqStack *&s)
{
int num;
while (!EmptyQueue(q)) //队不空时出队并入栈
{
deQueue(q, num);
Push(s, num);
}
printf("\n");
InitQueue(q); //队列初始化
while (!StackEmpty(s)) //栈不空时出栈并将元素入队
{
Pop(s, num);
enQueue(q, num);
}
Destroy(s);
}
程序分析:
- 运行结果: