暑假第一天算法学习之——循环链表的建立与删除模板———P1996 约瑟夫问题《算法竞赛》学习

一维数组建立单链表

1.头插法建立单链表

y总写的模板

//head储存表头,e[]存储节点值,ne【】储存节点next指针,idex表示当前用到的节点 
int head, idex ,e[],ne[],
void init()
{
	head=-1;
	idex=0;
}
 //头插
 //感觉跟数组没什么两样,但是这个可以作为逆序储存 
 void insert(int a)
 {
 	e[idex]=a;
 	ne[idex]=head;
 	head=idex++;
 }

2.双向链表

y总的模板,在竞赛中用静态的能加快编码速度

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

// 初始化
void init()
{
    //0是左端点,1是右端点
    r[0] = 1, l[1] = 0;
    idx = 2;
}

// 在节点a的右边插入一个数x
void insert(int a, int x)
{
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];
    l[r[a]] = idx, r[a] = idx ++ ;
}

// 删除节点a
void remove(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

作者:yxc
链接:https://www.acwing.com/blog/content/404/
来源:AcWing

约瑟夫问题

题目描述

n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

输入格式

输入两个整数 n , m n,m n,m

输出格式

输出一行 n n n 个整数,按顺序输出每个出圈人的编号。

样例 #1

样例输入 #1

10 3

样例输出 #1

3 6 9 2 7 1 8 5 10 4

提示

1 ≤ m , n ≤ 100 1 \le m, n \le 100 1m,n100

由题目分析最先想到的肯定是循环链表的建立与删除,主要能实现循环和删除
循环利用数组或者链表实现,删除利用双指针。
对于链表的实现用此题可以有多种解法,结合多个知识点
首先是最简单最方便的实现方法

题解

用一维数组实现单向静态链表

#include <iostream>
using namespace std;
int node[150];
int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n-1;i++)
    {
        node[i]=i+1;       //很巧妙
    }
    node[n]=1;//结尾等于开头,构成循环
    //以下是循环的思想跟后面解法的逻辑流程一样,
    int prev=1,now=1;    //从第一个开始
    while((n--)>1){
        for(int i=1;i<m;i++)
        {
            prev=now;now=node[now];//这一步理解很重要,保留前面节点,删除当前节点
        }
        printf("%d ",now);
        node[prev]=node[now];
        now=node[prev];
    }
    printf("%d",now);
    return 0;
}

动态单向链表实现

是“教科书式”的标准做法

#include "bits/stdc++.h"
struct node{
    int data;
    node *next;
};//定义链表的结构体

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    node *head,*p,*now,*prev;
    head=new node;head->data=1;head->next=NULL;
    now=head;//头指针指向头部
    for(int i=2;i<=n;i++)
    {
        p=new node;p->data=i;p->next=NULL;
        now->next=p;
        now=p;  //尾指针后移一个
    }
    now->next=head;//循环链表的建立
    //以上是建立链表,从头节点一步步建立起链表
    now=head,prev=head;//从第一个数开始
    while((n--)>1){
        for(int i=1;i<m;i++)
        {
            prev=now;
            now=now->next;
        }
        printf("%d ",now->data);
        prev->next=now->next;
        delete now;
        now=prev->next;
    }
    printf("%d",now->data);
    delete now;
    return 0;
}

用结构体数组实现单向静态链表

#include "stdio.h"
const int N=105;
struct node{
    int id,nextid;
    int data;//如果有必要定义一个有意义的数据
}node[N];//大数组定义在全局

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    node[0].nextid=1;
    for(int i=1;i<=n;i++)
    {
        node[i].id=i;node[i].nextid=i+1;
    }
    node[n].nextid=1;
    int now=1,prev=1;//双指针
    while((n--)>1)
    {
        for(int i=1;i<m;i++)
        {
            prev=now;now=node[now].nextid;
        }
        printf("%d ",node[now].id);
        node[prev].nextid=node[now].nextid;
        now=node[prev].nextid;
    }
    printf("%d",node[now].nextid);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值