1. 输入n(由用户输入)个10以内的数,每输入i(0≤i≤9)就把它插入到第i号队列中,最后把10个队中的非空队列按队列号从小到大的顺序串接成一条链,并输出该链的所有元素。
算法思想:建立一个队头指针数组quh和队尾指针数组qut,quh[i]和qut[j]表示i号(0≤i≤9)队列的队头和队尾,先将它们的所有元素置为NULL。对于输入的x,采用尾插法将其链到x号队列中。然后按0~9编号的顺序把这些队列中的结点构成
不带头结点的单链表,其首结点指针为head。最后输出单链表head的所有结点值并释放所有结点。
#include<stdio.h>
#include<malloc.h>
#define MAXQNode 10 //队列的个数
typedef struct QNode
{
int data;
struct QNode* next;
};
void Insert(QNode* quh[], QNode* qut[], int x) //将x插入到相应的队列中
{
QNode* s;
s = (QNode*)malloc(sizeof(QNode));
s->data = x;
s->next = NULL;
if (quh[x] == NULL)
{
quh[x] = s;
qut[x] = s;
}
else
{
qut[x]->next = s;
qut[x] = s;
}
}
void Create(QNode* quh[], QNode* qut[]) //根据用户的输入创建队列
{
int n, x;
printf("n:");
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
do {
printf("输入第%d个数:", i+1);
scanf("%d", &x);
} while (x<0||x>10);
Insert(quh, qut, x);
}
}
void DestroyList(QNode*& head) //释放单链表
{
QNode* pre = head, * p = pre->next;
while(p!=NULL)
{
free(pre);
pre = p;
p = p->next;
}
free(pre);
}
void DisplayList(QNode* head) //输出单链表的所有结点值
{
printf("\n输出所有元素:");
while (head != NULL)
{
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
QNode* Link(QNode* quh[], QNode* qut[]) //将非空队列链接起来并输出
{
QNode* head = NULL, * tail; //总链表的首结点指针和尾结点指针
for (int i = 0; i < MAXQNode; i++) //扫描所有队列
if (quh[i] != NULL) //i队列不空
{
if(head==NULL) //若i号队列为第一个非空队列
{
head = quh[i];
tail = qut[i];
}
else //若i号队列不是第一个非空队列
{
tail->next = quh[i];
tail = qut[i];
}
}
tail->next = NULL;
return head;
}
int main()
{
QNode* head;
QNode* quh[MAXQNode], * qut[MAXQNode];
for (int i = 0; i < MAXQNode; i++) quh[i] = qut[i] = NULL;
Create(quh, qut);
head = Link(quh, qut);
DisplayList(head);
DestroyList(head);
return 0;
}
程序分析
- 运行结果:
2. 将一个十进制正整数d转换为相应的二进制数
- 算法思想:将十进制正整数转换成二进制数通常采用除2取余数法。在转换过程中,二进制数是按照从低位到高位的次序得到的,这和通常的从高位到低位输出二进制的次序相反。为此设计一个栈s用于暂时存放每次得到的余数,当转换过程结束时,退栈所有元素便得到从高位到低位的二进制数。
void trans()
{
LinkStNode* s;
InitStack(s);
int n, num;
printf("输入一个十进制正整数:");
scanf("%d", &num);
do {
Push(s, num % 2);
num = num / 2;
} while (num);
while (!StackEmpty(s))
{
Pop(s, n);
printf("%d", n);
}
DestoryStack(s);
}
程序分析
- 运行结果:
3. 设计一个算法,利用顺序栈的基本运算从栈顶到栈底输出栈中的所有元素,要求仍保持栈中元素不变。
- 算法思想:先建立并初始化一个临时temp。退栈s中的所有元素,输出这些元素并进栈到temp中,然后将临时栈temp中的元素逐一出栈并进栈到s中,这样恢复s栈中原来的元素。
void diverse()
{
LinkStNode* s, * temp;
InitStack(s); InitStack(temp);
int n, num;
printf("输入:");
scanf("%d", &num);
while (num != 999)
{
s->data = num;
Push(s, s->data);
scanf("%d", &num);
}
while (!StackEmpty(s))
{
Pop(s, n);
printf("%d ", n);
Push(temp, n);
}
while (!StackEmpty(temp))
{
Pop(temp, n);
Push(s, n);
}
DestoryStack(temp);
}
程序分析
- !注意本题要求只能使用栈的基本运算来完成,不能直接用st->data[i]输出栈中的元素。
- 运行结果:
4. 利用顺序栈的基本运算求找中从栈顶到栈底的第k个元素,要求仍保持栈中元素不变。
-算法思想:先建立并初始化一个临时栈temp。退栈s中的所有元素x,并用i累计元素个数,当i==k时,将所有元素进栈到temp中,然后将临时栈temp中的元素逐出栈并进栈到s中,这样恢复s栈中原来的元素。如果中没有第k个元素,返回假;否则返回真。
bool diverse(int k)
{
LinkStNode* s, * temp;
InitStack(s); InitStack(temp);
int n, num;
printf("输入:");
scanf("%d", &num);
while (num != 999)
{
s->data = num;
Push(s, s->data);
scanf("%d", &num);
}
for (int i = 0; i < k; i++)
{
Pop(s, s->data);
Push(temp, s->data);
printf("%d ", s->data);
}
if (StackEmpty(s))
{
printf("\n栈中不存在第%d个元素", k);
return false;
}
else
{
while (!StackEmpty(temp))
{
Pop(temp, n);
Push(s, n);
}
return true;
}
DestoryStack(temp);
}
//printf("\n栈中有第k个元素吗?—%d",diverse(5));
程序分析
- !注意本题要求只能使用栈的基本运算来完成,不能直接用st->data[i]求第k个栈中元素。
- 运行结果:
5. 有abcde共n(n=5)个字符,通过一个栈可以产生多种出栈序列,判断序列str是否为一个合适的出栈序列,并给出操作过程,要求用相关数据进行测试。
- 算法思想:先建立一个字符顺序栈s,将进栈序列abcde存放到字符数组A中。用i、j分别扫描数组A和str,它们的初始值均为0。当数组A和str都没有扫描完时循环:比较栈顶元素e和str[j],若两者不相同,则将A[i]进栈,i加1;若两者相同,则出栈栈顶元素e,j加1。上述循环结束后退栈所有元素,如果序列str是一个合适的出栈序列,必有j==n,否则str不是一个合适的出栈序列。
bool isSerial(char str[])
{
LinkStNode* s;
InitStack(s);
char A[MaxSize], e;
int i, j = 0, k = 0;
for (i = 0; i < strlen(str); i++)
A[i] = 'a'+i;
while (j < strlen(str) && k < strlen(str))
{
if (StackEmpty(s) || (GetTop(s, e) && e != str[k]))
{
Push(s, A[j]);
printf("元素%c进栈\n", A[j]);
j++;
}
else
{
Pop(s, e);
printf("元素%c出栈\n", e);
k++;
}
}
while (!StackEmpty(s) && (GetTop(s, e)) && e == str[k])
{
Pop(s, e);
printf("元素%c出栈\n", e);
k++;
}
DestoryStack(s);
if (k == strlen(str)) return true;
else return false;
}
void Display(char str[])
{
for (int i = 0; i < strlen(str); i++)
printf("%c", str[i]);
}
int main()
{
char str[6] = { "acbde" };
Display(str);
printf("的操作序列:\n");
if (isSerial(str))
{
Display(str);
printf("是合适的出栈序列\n");
}
else
{
Display(str);
printf("不是合适的出栈序列\n");
}
return 0;
}
程序分析
{ ① 栈 s 为 空 , A [ i ] 元 素 直 接 入 栈 ② 栈 s 不 为 空 , 获 取 栈 顶 元 素 的 值 , 如 果 该 值 与 s t r [ j ] 的 值 不 相 等 , 则 将 栈 顶 元 素 出 栈 \begin{cases} ①栈s为空,A[i]元素直接入栈\\ ②栈s不为空,获取栈顶元素的值,如果该值与str[j]的值不相等,则将栈顶元素出栈\\ \end{cases} {①栈s为空,A[i]元素直接入栈②栈s不为空,获取栈顶元素的值,如果该值与str[j]的值不相等,则将栈顶元素出栈
- 运行结果:
6. 利用环形队列的基本运算返回指定队列中的队尾元素,要求算法的空间复杂度为O(1)。
- 算法思想:先求出队列q中的元素个数count,循环count次,出队一个元素num,再将元素num进队,最后的num即为队尾元素。
ElemType Last(CyQueue& q)
{
ElemType num;
int count = (q.rear - q.front + MaxSize) % MaxSize;
for (int i = 0; i < count; i++)
{
deQueue(q, num);
enQueue(q, num);
}
return num;
}
程序分析
- 由于算法要求空间复杂度为O(1),所以不能使用临时队列。
- 运行结果:
7. 删除队列中从队头开始的第k个元素的算法。
- 算法思想:先求出队列q中的元素个数count,若k小于0或大于count,返回假。出队所有元素,并记录元素的序号i,当i=k时对应的元素只出不进,否则将出队的元素又进队。
bool Delete(CyQueue& q, int k)
{
ElemType num;
int count = (q.rear - q.front + MaxSize) % MaxSize;
if (k<0 || k>count) return false;
for (int i = 0; i < count; i++)
{
deQueue(q, num);
if (i != k) enQueue(q, num);
}
return true;
}
程序分析
- 运行结果:
8. 假设有一个整型数组存放n个学生的分数,将分数分为3个等级,分数高于或等于90的为A等,分数低于60的为C等,其他为B等。要求采用双端队列,先输出A等分数,再输出C等分数,最后输出B等分数。
- 算法思想:设计双端队列的从队头出队算法deQueue1、从队头进队算法enQueue1和从队尾进队算法 enQueue2。对于含有n个分数的数组a,扫描所有元素a[i],若a[i]为A等,直接输出;若为B等,将其从队尾进队;若为C等,将其从队头进队。最后从队头出队并输出所有的元素。
bool enQueue1(DQueue& q, ElemType e) //从队头入队
{
if ((q.rear + 1) % MaxSize == q.front) return false; //队满
q.data[q.front] = e; //e元素入队
q.front = (q.front -1+ MaxSize) % MaxSize; //修改队头指针
return true;
}
bool enQueue2(DQueue& q, ElemType e) //从队尾进队算法
{
if ((q.rear + 1) % MaxSize == q.front) return false; //队满
q.rear = (q.rear + 1) % MaxSize; //修改队尾指针
q.data[q.rear] = e; //e元素入队
return true;
}
bool deQueue1(DQueue& q, ElemType &e) //从队头出队
{
if (q.rear == q.front) return false; //队空
q.front = (q.front + 1) % MaxSize; //修改队头指针
e = q.data[q.front];
return true;
}
void fun(int a[], int n)
{
ElemType e;
DQueue q;
InitQueue(q);
for(int i=0;i<n;i++)
{
if (a[i] >= 90) printf("%d ", a[i]);
else if (a[i] >= 60) enQueue2(q, a[i]); //从队尾进队
else enQueue1(q, a[i]); //从队头进队
}
while (!EmptyQueue(q))
{
deQueue1(q, e); //从队头出队
printf("%d ", e);
}
printf("\n");
}
程序分析
- 运行结果:
9. 用于列车编组的铁路转轨网络是一种栈结构,其中右边轨道是输入端、左边轨道是输出端。当右边轨道上的车皮编号顺序为1、2、3、4时,如果执行操作进栈、进栈、出栈、进栈、进栈、出栈、出栈、出栈,则在左边轨道上的车皮编号顺序为2、4、3、1。
设计一个算法,输入n个整数,表示右边轨道上n节车皮的编号,用上述转轨栈对这些车皮重新编排,使得编号为奇数的车皮都排在编号为偶数的车皮的前面。
- 算法思想:将转轨栈看成一个栈,将左边轨道看成是一个队列。从键盘逐个输入表示右边轨道上车皮编号的整数,根据其奇偶性做以下处理:若是奇数,则将其插入到表示左边轨道的顺序队列的队尾;若是偶数,则将其插入到表示转轨栈的顺序栈的栈顶。当n个整数都检测完之后,这些整数已全部进入队列或栈中。此时,首先按先进先出的顺序输出队列中的元素,然后再按后进先出的顺序输出中的元素。
算法中直接使用两个数组st和qu分别存放栈和队列中的元素。
void fun()
{
SqStack s;
InitStack(s);
SqQueue q;
InitQueue(q);
int n, x, i;
ElemType num;
printf("输入:n=");
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
printf("第%d个车皮编号:", i);
scanf("%d", &x);
if (x % 2 == 0)
{
Push(s, x);
printf("%d进栈\n", x);
}
else
{
enQueue(q, x);
printf("%d进队\n", x);
}
}
printf("列车出轨操作:\n");
while (!QueueEmpty(q))
{
deQueue(q, num);
printf("%d出队 ", num);
}
while (!StackEmpty(s))
{
Pop(s, num);
printf("%d出栈 ", num);
}
}
程序分析
- 运行结果:
10. 要求输出迷宫的所有路径,并求第一条最短路径长度及最短路径。
算法思想:Link:栈在迷宫问题中的应用
#include<stdio.h>
#define M 8 //行数
#define N 8 //列数
#define Maxsize 100 //栈最多元素个数
int mg[M + 2][N + 2] = { //ー个迷宫, 其四周加上均为1的外框
{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1} };
struct
{
int i, j;
int di;
}St[Maxsize], Path[Maxsize]; //定义栈和存放最短路径的数组
int top = -1; //栈顶指针
int count = 1; //路径数计数
int minlen = Maxsize; //最短路径长度
void dispapath() //输出一条路径并求最短路径
{
int k;
printf(" %5d: ", count++); //输出第count条路径
for (k = 0; k <= top; k++)
printf("(%d,%d)", St[k].i, St[k].j);
printf("\n");
if (top + 1 < minlen) //比较找最短路径
{
for (k = 0; k <= top; k++) //将最短路径存放在path中
Path[k] = St[k];
minlen = top + 1; //将最短路径长度存放在minlen中
}
}
void dispminpath() //输出第一条最短路径
{
printf("最短路径如下:\n");
printf("长度:%d\n", minlen);
printf("路径:");
for (int k = 0; k < minlen; k++)
printf("(%d,%d)", Path[k].i, Path[k].j);
printf("\n");
}
void mgpath(int xi, int yi, int xe, int ye)//求迷宫路径
{
int i, j, i1, j1, di;
bool find;
top++; //进栈
St[top].i = xi;
St[top].j = yi;
St[top].di = -1;
mg[xi][yi] = -1; //初始方块进栈
while (top > -1) //栈不空时循环
{
i = St[top].i; //取顶方块(i,j)
j = St[top].j;
di = St[top].di;
if (i == xe && j == ye) //找到了出口
{
dispapath(); //输出一条路径
mg[i][j] = 0; //让出口变为其他路径可走方块
top--; //出口退栈,即回退一个方块
i = St[top].i;
j = St[top].j;
di = St[top].di; //让栈顶方块变为当前方块
}
find = false; //找下一个可走方块(i1,j1)
while (di < 4 && !find)
{
di++;
switch (di)
{
case 0: i1 = i - 1; j1 = j; break;
case 1: i1 = i; j1 = j + 1; break;
case 2: i1 = i + 1; j1 = j; break;
case 3: i1 = i; j1 = j - 1; break;
}
if (mg[i1][j1] == 0) find = true;
}
if (find)//找到了下一个可走方块(i1,j1)//修改原機顶元素的di值
{
St[top].di = di;
top++;
St[top].i = i1;
St[top].j = j1;
St[top].di = -1; //下一个可走方块(11,j1)进栈
mg[i1][j1] = -1; //避免重复走到该方块
}
else //没有路径可走,则(i,j)方块退栈
{
mg[i][j] = 0; //让该位置变为其他路径可走方块
top--;
}
}
dispminpath(); //输出最短路径
}
int main()
{
printf("迷宫所有路径如下:\n");
mgpath(1, 1, M, N);
return 0;
}
程序分析
- 运行结果: