链表的定义: 链表是一种常见的一种数据结构,是一种线性表,但与数组不同的是,它的存储地址不是连续的,它的每一个节点都包含两部分,一个数据域,一个物理地址,链表正是通过存储的地址指向下一个节点,来实现数据连接;这个地址在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);
}
}
}