java实现单向链表的增删改查,循环链表实现解决约瑟夫问题.

链表的定义: 链表是一种常见的一种数据结构,是一种线性表,但与数组不同的是,它的存储地址不是连续的,它的每一个节点都包含两部分,一个数据域,一个物理地址,链表正是通过存储的地址指向下一个节点,来实现数据连接;这个地址在c,c++中叫指针,但在java中叫引用,正是这种方式的相比于数组,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理.但也导致查询速度相对于数组较慢.插入,删除相对较快.

链表分为单向链表,循环链表,和双向链表

1.单向链表实现

如何用java代码来实现单向链表呢?

1.首先我们要建一个节点类,直接采用了构造方法添加数据
  

class Node {
        int date;
        Node next;
        //构造方法
        public Node(int date) {
            this.date = date;
        }
    }

2.然后我们就可以吃创建一个单向链表,以及如何插入数据,删除数据

public class Link {
    Node head;
    //添加一个节点
    public void addNode(Node addNode) {
        //new一个节点,也就是要添加的节点
        if(head==null){
            head=addNode;
        }
        //不能直接对头结点操作,头结点是我们找到这个链表的头,要一直拿在手里
        //new 一个节点对象,做一个游动变量
        else{
            Node temp=head;
            while(temp.next!=null){
                temp=temp.next;
            }
            temp.next=addNode;
        }
    }
    
    //删除一个节点,需要删除的节点的数据,或者下标
    public boolean  deleteNode(int index){
        boolean flag=false;
        int count=1;
        //如果是头结点的操作
        if(index==1){
            head=head.next;
            flag=true;
        }else{
            //temp1为要删除节点
            //temp2为要删除节点的前一个节点
            Node temp1=head;
            Node temp2=head;
            while(count!=index){
                temp2=temp1;
                temp1=temp1.next;
                count++;
            }
            //判断是不是最后一个节点
            if(temp1.next==null){
                temp2.next=null;
                flag=true;
            }else{
                temp2.next=temp1.next;
                flag=true;
            }
        }
        
        return flag;
    }
    
    //插入一个节点
    public boolean insertNode(Node node,int index){
        int count=1;
        boolean flag=false;
        if(index==1){
            node.next=head;
            head=node;
            flag=true;
        }else{
            //temp1表示要插入位置的前一个节点
            //temp2表示要插入位置的后一个节点
            Node temp1=head;
            Node temp2=head;
            while(count!=index-1){
                temp1=temp1.next;
                temp2=temp1;
                count++;    
            }
            //判断是不是最后一个节点
            if(temp1.next==null){
                temp1.next=node;
                flag=true;
            }else{
                temp1.next=node;
                node.next=temp2;
                flag=true;
            }
                    
        }
        return flag;
        
    }
    public void showInfo(){
        Node temp=head;
        if(head!=null){
            while(temp.next!=null){
                System.out.print(temp.date+" ");
                temp=temp.next;
            }
            System.out.println();
        }
        
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Link link=new Link();
        //添加数据
        for(int i=1;i<=5;i++){
            System.out.println("1111");
            link.addNode(new Node(i));
        }
        
        link.showInfo();
        //删除数据
        link.deleteNode(1);
        link.showInfo();
        //插入数据
        link.insertNode(new Node(1), 1);
        link.showInfo();                                                  
    }

}

 注意:在操作链表过程中,头结点非常重要,不要直接对头结点直接操作,如果头结点找不到了,那么就无法找到链表中的数据了,因此一般再定义一个引用变量指向头结点进行操作,代码中有提到.

2:循环链表

循环链表:其实就是就是一个单向链表,但他的尾节点的引用指向了头结点,下面以非常经典的约瑟夫问题来了解循环链表.

  据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

那么如何用代码实现这个问题呢?循环链表就能很简单的实现这个问题

package LinkedList;
import java.util.Scanner;
public class ytsefu {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        CreatLink cl=new CreatLink();
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入游戏人数:");
        cl.peoplesum=sc.nextInt();
        System.out.print("请输入出列的数字:");
        cl.num=sc.nextInt();
        cl.creatLink();
        cl.showInfo();
        System.out.print("开始游戏(输入从几号开始):");
        cl.startNum=sc.nextInt();
        cl.playGame();
    }

}

class CreatLink{
    Node head;
    //链表的长度也就是游戏人数
    int peoplesum;
    //出队的数字
    int num;
    //从几号开始游戏
    int startNum;
    class Node{
        int data;
        Node next;
        public Node(int data){
            this.data=data;
        }
    }
    //创建循环链表
    public void creatLink(){
        Node temp=new Node(1);
        head=temp;
        for (int i = 2; i <=peoplesum; i++) {
                temp.next=new Node(i);
                temp=temp.next;
        }
        temp.next=head;
    }
    
    //找到开始游戏的人
    public Node startNum(){
        int count=1;
        Node temp=head;
        while(count!=startNum){
            temp=temp.next;
            count++;
        }
        return temp;
    }
    //开始游戏
    public void playGame(){
        Node temp=startNum();
        //出列的节点
        Node removeNode;
        int count=1;
        //循环链表中当只剩一个节点时,该节点的引用指向自己
        while(temp.next!=temp){
            for (int i = 2; i <num; i++) {
                temp=temp.next;
                //System.out.println(temp.data);
            }
            removeNode=temp.next;
            temp.next=temp.next.next;
            temp=removeNode.next;
            System.out.println("第"+count+"轮出列的为:"+removeNode.data+"号");
            count++;
        }
        System.out.println("\n最后胜利的为:"+temp.data+"号");
    }
    public void showInfo(){
        Node temp=head;
        if(head!=null){
            while(temp.next!=head){
                System.out.print(temp.data+" ");
                temp=temp.next;
            }
            System.out.println(temp.data);
        }
    }
}

本人新手,第一次学博客,哪里有不对的请多加指正.不胜感激!

 

转载于:https://www.cnblogs.com/bojers/p/7351112.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值