(一)线性结构(链表)题目

报数问题
问题描述:有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向。
  游戏开始,从1号小朋友开始顺时针报数,接下来每个小朋友的报数是上一个小朋友报的数加1。若一个小朋友报的数为k的倍数或其末位数(即数的个位)为k,则该小朋友被淘汰出局,不再参加以后的报数。当游戏中只剩下一个小朋友时,该小朋友获胜。
  例如,当n=5, k=2时:
  1号小朋友报数1;
  2号小朋友报数2淘汰;
  3号小朋友报数3;
  4号小朋友报数4淘汰;
  5号小朋友报数5;
  1号小朋友报数6淘汰;
  3号小朋友报数7;
  5号小朋友报数8淘汰;
  3号小朋友获胜。
  给定n和k,请问最后获胜的小朋友编号为多少?
输入格式
  输入一行,包括两个整数n和k,意义如题目所述。
输出格式
  输出一行,包含一个整数,表示获胜的小朋友编号。
样例输入
5 2
样例输出
3
样例输入
7 3
样例输出
4
数据规模和约定
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 9。
要求:利用单向循环链表存储结构模拟此过程。

代码

#include <bits/stdc++.h>
using namespace std;
typedef struct node
{
    int data;
    struct node *next,*prior;
}node,*linklist;
int n,k;
linklist L;//头指针
bool judge(int x)
{
    if(x%k==0||x%10==k)return 1;//被淘汰
    return 0;
}
void build(linklist &L)//建立双向循环链表(无尾指针)
{
    L=new node;
    L->data=1;//头指针储存元素
    linklist r=L;
    linklist s;
    for(int i=2;i<=n;i++)
    {
        s=new node;
        s->data=i;
        s->prior=r;
        r->next=s;
        r=s;
    }
    r->next=L;
    L->prior=r;
}
void output()
{
    linklist p=L;
    for(int i=1;i<=n;i++)
    {
        printf("%d\n",p->data);
        p=p->next;
    }
}
int solve(linklist L)
{
    int cnt=0,num=0;
    linklist p=L;
    while(1)
    {
        if(cnt==n-1)//淘汰个数cnt
            return p->data;
        num++;//报数为num
        if(judge(num))
        {
            p->prior->next=p->next;
            p->next->prior=p->prior;
            linklist tmp=p;
            p=p->next;
            cnt++;
            delete tmp;
        }
        else p=p->next;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    build(L);
    //output();
    int ans=solve(L);
    printf("%d\n",ans);
    return 0;
}

(二)栈和队列题目

迷宫问题求解
任务:可以输入一个任意大小的迷宫数据,用非递归的方法求出一条走出迷宫的路径,并将路径输出;
要求:在上交资料中请写明:存储结构、基本算法(可以使用程序流程图)、源程序、测试数据和结果、算法的时间复杂度、另外可以提出算法的改进方法;

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
char a[N][N];
bool vis[N][N];
int n,m,bx,by,ex,ey;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
    int x,y,cnt;
}pre[N][N],path[N*N];
queue<node>q;
int bfs()
{
    q.push({bx,by,0});
    while(!q.empty())
    {
        node tmp=q.front();q.pop();
        int x=tmp.x,y=tmp.y,cnt=tmp.cnt;
        if(x==ex&&y==ey)return cnt;
        vis[x][y]=1;
        for(int i=0;i<4;i++)
        {
            int nx=x+dir[i][0];
            int ny=y+dir[i][1];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!vis[nx][ny]&&a[x][y]=='0')
            {
                q.push({nx,ny,cnt+1});
                pre[nx][ny].x=x;
                pre[nx][ny].y=y;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;//输入迷宫大小
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];//输入迷宫
    cin>>bx>>by>>ex>>ey;//输入起点和终点坐标
    int ans=bfs();
    printf("%d\n",ans);//输出最短步数
    int nx=ex,ny=ey;
    int cnt=0;
    while(1)
    {
        path[++cnt]={nx,ny};
        if(nx==bx&&ny==by)break;
        int t1=nx,t2=ny;
        nx=pre[t1][t2].x;
        ny=pre[t1][t2].y;

    }
    for(int i=cnt;i>=1;i--)//输出最短路径
        printf("(%d, %d)\n",path[i].x,path[i].y);
    return 0;
}

测试数据

输入格式
  输入两个整数n和m,表示n*m大小的迷宫。
  输入n行,表示迷宫,0表示可走的路,1表示墙。
  输入起点坐标bx、by。
  输入终点坐标ex、ey。
输出格式
  输出一行,包含一个整数cnt,表示最短步数。
  输出cnt行,表示起点到终点的最短路径,格式如样例所示。

test_01
输入:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
1 1
5 5
输出:
8
(1, 1)
(2, 1)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(3, 5)
(4, 5)
(5, 5)

test_02
输入:
17 54
011111111111111111111111111111111111111111111111111111
011111100000001111111111111111111111111111111101111111
011111101111011111111111111111111111111111110000000011
000000001111011111100000000001111111111111111101111111
111111101111011111101111111111111111111111111101111111
111111101111011111101111111111111111111111111101111111
111111101111011111101111111111111111111111111101111111
111111101111011111100000000000000000011111111101111111
111111101111011111101111111111111111011111111101111111
111111100000000000001111111111111111011111111101111111
111111111111111111111111111111111111011111111101111111
111111111111111111000000000000000000011000000001111111
111111111111111111011111111111111111111011111101111111
111111111111111111011111111111111111111011111101111111
111111111111111111011111111111111111111011111100000011
111111111111111111000000000000000000000011111111111001
111111111111111111111111111111111111111111111111111100
1 1
17 54
输出:
117
(1, 1)
(2, 1)
(3, 1)
(4, 1)
(4, 2)
(4, 3)
(4, 4)
(4, 5)
(4, 6)
(4, 7)
(4, 8)
(5, 8)
(6, 8)
(7, 8)
(8, 8)
(9, 8)
(10, 8)
(10, 9)
(10, 10)
(10, 11)
(10, 12)
(10, 13)
(10, 14)
(10, 15)
(10, 16)
(10, 17)
(10, 18)
(10, 19)
(10, 20)
(9, 20)
(8, 20)
(8, 21)
(8, 22)
(8, 23)
(8, 24)
(8, 25)
(8, 26)
(8, 27)
(8, 28)
(8, 29)
(8, 30)
(8, 31)
(8, 32)
(8, 33)
(8, 34)
(8, 35)
(8, 36)
(8, 37)
(9, 37)
(10, 37)
(11, 37)
(12, 37)
(12, 36)
(12, 35)
(12, 34)
(12, 33)
(12, 32)
(12, 31)
(12, 30)
(12, 29)
(12, 28)
(12, 27)
(12, 26)
(12, 25)
(12, 24)
(12, 23)
(12, 22)
(12, 21)
(12, 20)
(12, 19)
(13, 19)
(14, 19)
(15, 19)
(16, 19)
(16, 20)
(16, 21)
(16, 22)
(16, 23)
(16, 24)
(16, 25)
(16, 26)
(16, 27)
(16, 28)
(16, 29)
(16, 30)
(16, 31)
(16, 32)
(16, 33)
(16, 34)
(16, 35)
(16, 36)
(16, 37)
(16, 38)
(16, 39)
(16, 40)
(15, 40)
(14, 40)
(13, 40)
(12, 40)
(12, 41)
(12, 42)
(12, 43)
(12, 44)
(12, 45)
(12, 46)
(12, 47)
(13, 47)
(14, 47)
(15, 47)
(15, 48)
(15, 49)
(15, 50)
(15, 51)
(15, 52)
(16, 52)
(16, 53)
(17, 53)
(17, 54)

附:POJ 迷宫问题简化版

POJ 3984 迷宫问题

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int N=1e3+10;
char a[N][N];
bool vis[N][N];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
    int x,y,cnt;
}pre[N][N],path[N*N];
queue<node>q;
void bfs()
{
    q.push({0,0,0});
    while(!q.empty())
    {
        node tmp=q.front();q.pop();
        int x=tmp.x,y=tmp.y,cnt=tmp.cnt;
        if(x==4&&y==4)return;
        vis[x][y]=1;
        for(int i=0;i<4;i++)
        {
            int nx=x+dir[i][0];
            int ny=y+dir[i][1];
            if(nx>=0&&nx<5&&ny>=0&&ny<5&&!vis[nx][ny]&&a[x][y]=='0')
            {
                q.push({nx,ny,cnt+1});
                pre[nx][ny].x=x;
                pre[nx][ny].y=y;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            cin>>a[i][j];
    bfs();
    int nx=4,ny=4;
    int cnt=0;
    while(1)
    {
        path[++cnt]={nx,ny};
        if(nx==0&&ny==0)break;
        int t1=nx,t2=ny;
        nx=pre[t1][t2].x;
        ny=pre[t1][t2].y;
    }
    for(int i=cnt;i>=1;i--)
        printf("(%d, %d)\n",path[i].x,path[i].y);
    return 0;
}

(三)树型结构题目

二叉树的构造
任务:已知二叉树的层序和中序遍历序列,或已知二叉树的先序序列、中序序列,试编写算法建立该二叉树( 用递归或非递归的方法都可以)。
要求:能够输入树的各个结点,并能够输出用不同方法遍历的遍历序列;分别建立建立二叉树存储结构的的输入函数、输出层序遍历序列的函数、输出先序遍历序列的函数;

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef struct node
{
    char data;
    struct node *lchild,*rchild;
}node,*Tree;
char pre[N],mid[N];
int get_pos(char s,int l,int r)
{
    for(int i=l;i<=r;i++)
        if(mid[i]==s)return i;
    return -1;
}
void build(Tree &T,int i,int l,int r)//i是遍历到的先序的位置,[l,r]是中序子表的左右端点
{
    int pos=get_pos(pre[i],l,r);//pos是由先序的i位置得到在中序的位置
    if(pos==-1){T=NULL;return;}
    T=new node;
    T->data=pre[i];
    build(T->lchild,i+1,l,pos-1);
    build(T->rchild,i+pos-l+1,pos+1,r);
}
void pre_travel(Tree T)//先序遍历
{
    if(T==NULL)return;
    printf("%c",T->data);
    pre_travel(T->lchild);
    pre_travel(T->rchild);
}
void mid_travel(Tree T)//中序遍历
{
    if(T==NULL)return;
    mid_travel(T->lchild);
    printf("%c",T->data);
    mid_travel(T->rchild);
}
void post_travel(Tree T)//后序遍历
{
    if(T==NULL)return;
    post_travel(T->lchild);
    post_travel(T->rchild);
    printf("%c",T->data);
}
void level_travel(Tree T)//层次遍历
{
    queue<Tree>q;
    q.push(T);
    while(!q.empty())
    {
        Tree x=q.front();q.pop();
        printf("%c",x->data);
        if(x->lchild)q.push(x->lchild);
        if(x->rchild)q.push(x->rchild);
    }
}
void output(Tree T)
{
    printf("\n先序遍历:");
    pre_travel(T);
    printf("\n");
    printf("中序遍历:");
    mid_travel(T);
    printf("\n");
    printf("后序遍历:");
    post_travel(T);
    printf("\n");
    printf("层次遍历:");
    level_travel(T);
    printf("\n");
}
int main()
{
    Tree T;
    printf("请输入前序序列:");
    cin>>pre+1;
    printf("请输入中序序列:");
    cin>>mid+1;
    int n=strlen(pre+1);
    build(T,1,1,n);
    output(T);
    return 0;
}

测试数据

输入:
ABDEFCHKGJ
DBFEAHKCJG
输出:
先序遍历:ABDEFCHKGJ
中序遍历:DBFEAHKCJG
后序遍历:DFEBKHJGCA
层次遍历:ABCDEHGFKJ

(四)图型结构题目

拓扑排序
任务:编写函数实现图的拓扑排序。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n,m,x,y,cnt,d[N],ans[N];
typedef struct arcnode
{
    int to;
    struct arcnode *next;
}edge;
struct node
{
    int data;
    edge *head;
}v[N];
void add(int x,int y)
{
    edge *s=new edge;
    s->to=y;
    s->next=v[x].head;
    v[x].head=s;
}
void topo_sort()//拓扑排序
{
    int s[N],top=-1;//手写栈,用数组模拟栈s,指针为top
    for(int i=1;i<=n;i++)
        if(!d[i])s[++top]=i;//将入度为0的点入栈
    while(top>-1)
    {
        int x=s[top];top--;
        ans[++cnt]=x;
        for(edge *p=v[x].head;p!=NULL;p=p->next)
        {
            int y=p->to;
            d[y]--;//y的入度减1
            if(!d[y])s[++top]=y;//将入度为0的点入栈
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i].data;
        v[i].head=NULL;
    }
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;
        d[y]++;//统计每个点的入度
        add(x,y);
    }
    topo_sort();
    for(int i=1;i<=cnt;i++)
        i==cnt?printf("v%d\n",ans[i]):printf("v%d ",ans[i]);
    return 0;
}

测试数据

输入:
12 16
1 2 3 4 5 6 7 8 9 10 11 12
1 4
1 2
1 3
1 12
4 5
2 3
3 5
3 7
5 7
3 8
9 12
9 10
10 12
9 11
11 6
6 8
输出:
v9 v10 v11 v6 v1 v4 v2 v3 v5 v7 v8 v12

(五)查找、排序、文件

散列表的插入、删除和查找
功能要求:
(1)初始化散列表;
(2)向散列表中插入一个元素;
(3)从散列表中删除一个元素;
(4)从散列表中查找一个元素。
散列表通常采用链接法处理冲突,散列文件中每个节点的类型定义为:
Struct FLNode
{ //散列主文件中的节点类型
ElemType data ; //值域
Int *next; //指向下一个节点的指针域
};
其中data域用来存储待散列的元素,next域用来存储下一个同义词元素在散列表中的存储位置,即所在节点的位置号。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=20,mod=13;//哈希函数H(x)=x%mod
typedef struct node
{
    int data;
    struct node *next;
}node,*linklist;
int n,x;
linklist L[N];
void init()//初始化散列表
{
    for(int i=0;i<mod;i++)
    {
        L[i]=new node;
        L[i]->next=NULL;
    }
}
void insert_L(int x)//插入x
{
    int y=x%mod;//哈希函数H(x)=x%mod
    linklist head=L[y];
    linklist s=new node;
    s->data=x;
    s->next=head->next;
    head->next=s;
}
void output()//输出散列表
{
    for(int i=0;i<mod;i++)
    {
        printf("%d:",i);
        linklist p=L[i]->next;
        while(p)
        {
            if(p->next)printf("%d ",p->data);
            else printf("%d",p->data);
            p=p->next;
        }
        printf("\n");
    }
}
void seek(int x)//查找x
{
    int y=x%mod;
    linklist p=L[y]->next;
    int cnt=0;
    while(p)
    {
        cnt++;
        if(p->data==x)
        {
            printf("查找成功!\n");
            printf("查找的元素 %d 在第 %d 个链表的第 %d 个节点\n",x,y,cnt);
            return;
        }
        p=p->next;
    }
    printf("查找失败!\n");
}
void del(int x)//删除x
{
    int y=x%mod;
    linklist p=L[y];
    while(p->next)
    {
        if(p->next->data==x)
        {
            linklist tmp=p->next;
            p->next=tmp->next;
            delete tmp;
            printf("删除成功!\n当前散列表:\n");
            output();
            return;
        }
        p=p->next;
    }
    printf("要删除的节点不存在!\n");
}
int main()
{
    ios::sync_with_stdio(false);
    init();
    printf("请输入若干个数插入到散列表中(输入0时结束输入):\n");
    while(cin>>x&&x)
    {n++;insert_L(x);}
    printf("\n当前散列表:\n");
    output();
    printf("\n请输入要查找的元素:\n");
    cin>>x;
    seek(x);
    printf("\n请输入要删除的元素:\n");
    cin>>x;
    del(x);
    return 0;
}

测试数据

test_01
输入:
19 14 23 1 68 20 84 27 55 11 10 79 0
55
55
输出:
在这里插入图片描述

test_02
输入:
19 14 23 1 68 20 84 27 55 11 10 79 0
100
100
输出:
在这里插入图片描述