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); } } }
本人新手,第一次学博客,哪里有不对的请多加指正.不胜感激!