链表的基本操作

单链表的简单介绍:

链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;
链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;
其中每个结点都有指针成员变量指向列表中的下一个结点;
链表是由结点构成,head指针指向第一个成为表头的结点,而终止于最后一个指向NULL的指针。一般使用时都要定义一个头结点,头结点不存放数据,只是为了方便查找。

本文介绍的链表操作有(定义头结点):

1.单链表的基本操作(增,删,改,查);

2.按顺序插入节点;

3.获取链表节点个数与查找链表中倒数第K个节点;

4.单链表的反转;

5.合并两个链表;

6.双向链表的基本操作(增,删,改,查);

7.环状链表解决约瑟夫问题;

1.单链表的基本操作(增,删,改,查):

代码如下: 

package com.mrz.test;

public class SingleLinkedList {

	public static void main(String[] args) {
		SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
		
		//创建五个节点
		HeroNode node1 = new HeroNode(1, "刘备");
		HeroNode node2 = new HeroNode(2, "关羽");
		HeroNode node3 = new HeroNode(3, "张飞");
		HeroNode node4 = new HeroNode(4, "吕布");
		HeroNode node5 = new HeroNode(5, "貂蝉");
		
		//添加节点
		singleLinkedListDemo.addHeroNode(node1);
		singleLinkedListDemo.addHeroNode(node2);
		singleLinkedListDemo.addHeroNode(node3);
		singleLinkedListDemo.addHeroNode(node4);
		singleLinkedListDemo.addHeroNode(node5);
		
		
		//显示节点
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
		
		System.out.println("-----------------------");
		
		//修改貂蝉为西施
		singleLinkedListDemo.updataLinkedList(new HeroNode(5, "西施"));
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
		
		System.out.println("-----------------------");
		
		//删除节点
		singleLinkedListDemo.delLinkedList(5);
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
	}
}



class SingleLinkedListDemo{
	private HeroNode head = new HeroNode(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode getHead() {
		return head;
	}
	
	//添加节点
	public void addHeroNode(HeroNode heroNode) {
		//因为head节点是不能动的,因此我们需要一个辅助节点temp
		HeroNode temp = head;
		//添加数据是从链表的最后添加;
		//如何确认最后的位置,只能     节点.next 这样遍历下去,直到值为null就找到位置
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		temp.next = heroNode;
	}
	
	
	
	//显示链表
	public void showLinkedList(HeroNode head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			System.out.println(temp);
			temp = temp.next;
		}
	}
	
	
	//1.刘备  2.关羽   3.张飞
	//if(temp.id = hearoNode.id) temp.name = heroNode.name
	//修改链表节点数据
	public void updataLinkedList(HeroNode heroNode) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		//定义一个辅助节点
		HeroNode temp = head.next;
		boolean flag = false;
		//是否找到对应节点
		while(true) {
			//如果找到
			if(temp.id == heroNode.id) {
				flag = true;
				break;
			}
			//防止空指针报错
			if(temp.next == null) {
				break;
			}
			temp = temp.next;		//temp后移
		}
		
		if(flag) {
			temp.name = heroNode.name;
		}else {
			System.out.println("没有找到id为" + heroNode.id);
		}
	}
	
	
	
	
	//删除节点
	public void delLinkedList(int id) {
		HeroNode temp = head;
		boolean flag = false;
		//找到待删除节点的前一个节点
		while(true) {
			//已经遍历到最后,需要跳出循环
			if(temp.next == null) {
				break;
			}
			
			//找到
			if(temp.next.id == id) {
				flag = true;
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//next是下一个,而next.next就是下下个,实现跳过中间的(删除)
			temp.next = temp.next.next;
		}else {
			System.out.println("没有找到id为" + id);
		}
	}
	
	
	

}



//相当于一个节点
class HeroNode{
	public int id;
	public String name;
	public HeroNode next;		//用来指向下一个节点
	
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
	
	
}

2.以上的插入是按顺序插入的,所以输出的也是顺序输出的,但是如果你先插入的是第二条(id为2),再插入第一条(id为1),这时按照上面的方法打印的就是先打印id为2的再打印id为1的,而工作中往往需要插入时能按照顺序插入,那么就有了编号排序插入的方法(在插入时对id做了比较),代码如下:

package com.mrz.test;

public class SingleLinkedList {

	public static void main(String[] args) {
		SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
		
		//创建五个节点
		HeroNode node1 = new HeroNode(1, "刘备");
		HeroNode node2 = new HeroNode(2, "关羽");
		HeroNode node3 = new HeroNode(3, "张飞");
		HeroNode node4 = new HeroNode(4, "吕布");
		HeroNode node5 = new HeroNode(5, "貂蝉");
		
		//按顺序添加节点
		singleLinkedListDemo.addReorder(node3);
		singleLinkedListDemo.addReorder(node1);
		singleLinkedListDemo.addReorder(node5);
		singleLinkedListDemo.addReorder(node4);
		singleLinkedListDemo.addReorder(node2);
		
		
		//显示节点
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
		
	}
}



class SingleLinkedListDemo{
	private HeroNode head = new HeroNode(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode getHead() {
		return head;
	}
	
	
	
	
	//显示链表
	public void showLinkedList(HeroNode head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			System.out.println(temp);
			temp = temp.next;
		}
	}
	
	
	
	//编号排序插入
	public void addReorder(HeroNode heroNode) {
		HeroNode temp = head;
		boolean flag = false;
		while(true) {
			//链表到最后
			if(temp.next == null) {
				flag = true;
				break;
			}else if (temp.next.id > heroNode.id) {
				flag = true;
				break;
			}else if (temp.next.id == heroNode.id) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//新的节点指向temp指向下一个节点
			heroNode.next = temp.next;
			//temp节点指向新的节点
			temp.next = heroNode;
		}else {
			//id重复
			System.out.println("id" + heroNode.id + "重复");
		}
	}
	
	

}



//相当于一个节点
class HeroNode{
	public int id;
	public String name;
	public HeroNode next;		//用来指向下一个节点
	
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
	
	
}

3.获取链表节点个数与查找链表中倒数第K个节点:

package com.mrz.test;

public class SingleLinkedList {

	public static void main(String[] args) {
		SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
		
		//创建五个节点
		HeroNode node1 = new HeroNode(1, "刘备");
		HeroNode node2 = new HeroNode(2, "关羽");
		HeroNode node3 = new HeroNode(3, "张飞");
		HeroNode node4 = new HeroNode(4, "吕布");
		HeroNode node5 = new HeroNode(5, "貂蝉");
		
		//添加节点
		singleLinkedListDemo.addReorder(node3);
		singleLinkedListDemo.addReorder(node1);
		singleLinkedListDemo.addReorder(node5);
		singleLinkedListDemo.addReorder(node4);
		singleLinkedListDemo.addReorder(node2);
		
		
		//显示节点
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
		System.out.println("节点的有效个数为" + getLinkedLength(singleLinkedListDemo.getHead()));
		System.out.println("倒数第三个节点为:" + findIndexReciprocal(singleLinkedListDemo.getHead(), 3));
		
		
	}
	
	
	//查找链表节点的个数,涉及到遍历,所以我们要传一个头节点进来
		public static int getLinkedLength(HeroNode head) {
			//判断链表是否为空,头结点不算在内
			if(head.next == null)
				return 0;
			HeroNode temp = head.next;
			int length = 0;
			//为什么这里是temp!=null,而不是temp.next!=null
			//因为我已经在上面temp = head.next,此时temp指向的是后面的节点了
			while(temp != null) {
				length ++;
				temp = temp.next;
			}
			return length;
		}
		
		
		//查找单链表中倒数第K个节点
		public static HeroNode findIndexReciprocal(HeroNode head,int index) {
			//判断链表是否为空
			if(head.next == null) {
				return null;
			}
			int length = getLinkedLength(head);
			//判断index是否合法
			if (index > length || index <= 0) {
				return null;
			}
			//临时辅助
			HeroNode temp = head.next;
			
			for(int i = 0; i < length - index; i++) {
				temp = temp.next;
			}
			//返回节点
			return temp;
			
		}
		
		
	
	
}






class SingleLinkedListDemo{
	private HeroNode head = new HeroNode(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode getHead() {
		return head;
	}
	
	//添加节点
	public void addHeroNode(HeroNode heroNode) {
		//因为head节点是不能动的,因此我们需要一个辅助节点temp
		HeroNode temp = head;
		//添加数据是从链表的最后添加;
		//如何确认最后的位置,只能     节点.next 这样遍历下去,直到值为null则说明找到了最后的位置
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		temp.next = heroNode;		//将新节点添加进去即可
	}
	
	
	
	//显示链表
	public void showLinkedList(HeroNode head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			System.out.println(temp);
			temp = temp.next;
		}
	}
	
	
	
	
	//编号排序插入
	public void addReorder(HeroNode heroNode) {
		HeroNode temp = head;
		boolean flag = false;
		while(true) {
			//链表到最后
			if(temp.next == null) {
				flag = true;
				break;
			}else if (temp.next.id > heroNode.id) {
				flag = true;
				break;
			}else if (temp.next.id == heroNode.id) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//新的节点指向temp指向下一个节点
			heroNode.next = temp.next;
			//temp节点指向新的节点
			temp.next = heroNode;
		}else {
			//id重复
			System.out.println("id" + heroNode.id + "重复");
		}
	}
	
	
	

}



//相当于一个节点
class HeroNode{
	public int id;
	public String name;
	public HeroNode next;		//用来指向下一个节点
	
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
	
	
}

4.单链表的反转(两种方法,区别在代码注释已经写好了,详细见注释):

 

 

 

package com.mrz.test;

import java.util.Stack;

public class SingleLinkedList {

	public static void main(String[] args) {
		SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
		
		//创建五个节点
		HeroNode node1 = new HeroNode(1, "刘备");
		HeroNode node2 = new HeroNode(2, "关羽");
		HeroNode node3 = new HeroNode(3, "张飞");
		HeroNode node4 = new HeroNode(4, "吕布");
		HeroNode node5 = new HeroNode(5, "貂蝉");
		
		//添加节点
		singleLinkedListDemo.addReorder(node3);
		singleLinkedListDemo.addReorder(node1);
		singleLinkedListDemo.addReorder(node5);
		singleLinkedListDemo.addReorder(node4);
		singleLinkedListDemo.addReorder(node2);
		
		
		//显示节点
		
		//反转链表
		LinkedReverse(singleLinkedListDemo.getHead());
		singleLinkedListDemo.showLinkedList(singleLinkedListDemo.getHead());
		

        System.out.println("-----------------------");


		//利用栈反转链表
		LinkedReverseDoStack(singleLinkedListDemo.getHead());
		
	}
	
	
		
		
		//将单链表反转
		public static void LinkedReverse(HeroNode head) {
			//判断链表是否为空,链表有效节点为1则不用反转
			if(head.next == null || head.next.next == null) {
				return;
			}
			//定义辅助的指针变量
			HeroNode temp = head.next;
			HeroNode next = null;
			//新建一个指向当前节点的reverseHed
			HeroNode reverseHead = new HeroNode(0, "");
			
			//遍历原来的节点,每次遍历都取出来放入reverseHead的最前面
			while(temp != null) {
				//暂时保存当前节点的下一个节点
				next = temp.next;
				//将数据指向reverseHead这个链表的前端     第一次temp.next是null
				temp.next = reverseHead.next;
				//指向当前的节点,不然得到会是null
				reverseHead.next = temp;
				temp = next;
			}
			
			//reverseHead这个链表里就是反转后的链表,所以head指向的reverseHead就是得到一个反转的链表
			head.next = reverseHead.next;
		}
	
		
		//利用栈来解决逆序(与上面方法区别是,栈方法只是反向打印,并没有生成反向的链表)
		public static void LinkedReverseDoStack(HeroNode head) {
			if(head.next == null) {
				return;
			}
			Stack<HeroNode> stack = new Stack<HeroNode>();
			HeroNode temp = head.next;
			while(temp != null) {
				stack.push(temp);
				temp = temp.next;
			}
			while(stack.size() > 0) {
				System.out.println(stack.pop());
			}
		}
		
	
}






class SingleLinkedListDemo{
	private HeroNode head = new HeroNode(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode getHead() {
		return head;
	}
	
	//添加节点
	public void addHeroNode(HeroNode heroNode) {
		//因为head节点是不能动的,因此我们需要一个辅助节点temp
		HeroNode temp = head;
		//添加数据是从链表的最后添加;
		//如何确认最后的位置,只能     节点.next 这样遍历下去,直到值为null则说明找到了最后的位置
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		temp.next = heroNode;		//将新节点添加进去即可
	}
	
	
	
	//显示链表
	public void showLinkedList(HeroNode head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			System.out.println(temp);
			temp = temp.next;
		}
	}
	
	
	
	
	//编号排序插入
	public void addReorder(HeroNode heroNode) {
		HeroNode temp = head;
		boolean flag = false;
		while(true) {
			//链表到最后
			if(temp.next == null) {
				flag = true;
				break;
			}else if (temp.next.id > heroNode.id) {
				flag = true;
				break;
			}else if (temp.next.id == heroNode.id) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//新的节点指向temp指向下一个节点
			heroNode.next = temp.next;
			//temp节点指向新的节点
			temp.next = heroNode;
		}else {
			//id重复
			System.out.println("id" + heroNode.id + "重复");
		}
	}
	
	
	

}



//相当于一个节点
class HeroNode{
	public int id;
	public String name;
	public HeroNode next;		//用来指向下一个节点
	
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
	
	
}

5.合并两个链表(新建一个辅助链表,然后根据第一个链表和第二个链表id插入即可):

package com.mrz.test;

import java.util.Stack;

public class SingleLinkedList {

	public static void main(String[] args) {
		SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
		
		//创建五个节点
		HeroNode node1 = new HeroNode(1, "刘备");
		HeroNode node2 = new HeroNode(2, "关羽");
		HeroNode node3 = new HeroNode(3, "张飞");
		HeroNode node4 = new HeroNode(4, "吕布");
		HeroNode node5 = new HeroNode(5, "貂蝉");
		
		//添加节点
		singleLinkedListDemo.addReorder(node3);
		singleLinkedListDemo.addReorder(node1);
		singleLinkedListDemo.addReorder(node5);
		singleLinkedListDemo.addReorder(node4);
		singleLinkedListDemo.addReorder(node2);
		
		
		//新建一个节点
		SingleLinkedListDemo singleLinkedListDemo2 = new SingleLinkedListDemo();
		HeroNode node6 = new HeroNode(6, "马超");
		HeroNode node7 = new HeroNode(7, "赵云");
		singleLinkedListDemo.addReorder(node6);
		singleLinkedListDemo.addReorder(node7);
		System.out.println("合并后的链表");
		mergeLinked(singleLinkedListDemo.getHead(), singleLinkedListDemo2.getHead());
	}
	
		
		
		
		
		
		//两个链表合并
		public static void mergeLinked(HeroNode head1,HeroNode head2) {
			//辅助指针变量
			HeroNode temp1 = head1.next;
			HeroNode temp2 = head2.next;
			
			//创建一个中间临时链用来合并
			HeroNode head3 = new HeroNode(0, "");
			HeroNode temp3 = head3;
			
			//合并三种情况
			//temp1此时还有数据  temp2没有数据  就把temp1的数据加入临时链表
			//temp2此时还有数据  temp1没有数据  就把temp2的数据加入临时链表
			//都还有数据
			while(temp1 != null || temp2 != null) {
				if(temp1 != null && temp2 == null) {
					temp3.next = temp1;
					temp1 = temp1.next;
				}else if (temp2 != null && temp1 == null) {
					temp3.next = temp2;
					temp2 = temp2.next;
				}else {
					if(temp1.id < temp2.id) {
						temp3.next = temp1;
						temp1 = temp1.next;
					}else {
						temp3.next = temp2;
						temp2 = temp2.next;
					}
				}
				
				//后移
				temp3 = temp3.next;
			}
			SingleLinkedListDemo singleLinkedListDemo = new SingleLinkedListDemo();
			singleLinkedListDemo.showLinkedList(head3);
		}
		
		
	
}






class SingleLinkedListDemo{
	private HeroNode head = new HeroNode(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode getHead() {
		return head;
	}
	
	//添加节点
	public void addHeroNode(HeroNode heroNode) {
		//因为head节点是不能动的,因此我们需要一个辅助节点temp
		HeroNode temp = head;
		//添加数据是从链表的最后添加;
		//如何确认最后的位置,只能     节点.next 这样遍历下去,直到值为null则说明找到了最后的位置
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		temp.next = heroNode;		//将新节点添加进去即可
	}
	
	
	
	//显示链表
	public void showLinkedList(HeroNode head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			System.out.println(temp);
			temp = temp.next;
		}
	}
	
	
	
	
	//编号排序插入
	public void addReorder(HeroNode heroNode) {
		HeroNode temp = head;
		boolean flag = false;
		while(true) {
			//链表到最后
			if(temp.next == null) {
				flag = true;
				break;
			}else if (temp.next.id > heroNode.id) {
				flag = true;
				break;
			}else if (temp.next.id == heroNode.id) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//新的节点指向temp指向下一个节点
			heroNode.next = temp.next;
			//temp节点指向新的节点
			temp.next = heroNode;
		}else {
			//id重复
			System.out.println("id" + heroNode.id + "重复");
		}
	}
	
	
	

}



//相当于一个节点
class HeroNode{
	public int id;
	public String name;
	public HeroNode next;		//用来指向下一个节点
	
	public HeroNode(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
	
	
}

6.双向链表的基本操作(增,删,改,查):

package com.mrz.test;

/*
 * 2022-04-27
 * mrz
 * 双向链表的基本操作
 */
public class DoubleLinkedList {

	public static void main(String[] args) {
		DoubleLinkedListDemo doubleLinkedListDemo = new DoubleLinkedListDemo();
		
		//创建五个节点
		HeroNode2 node1 = new HeroNode2(1, "刘备");
		HeroNode2 node2 = new HeroNode2(2, "关羽");
		HeroNode2 node3 = new HeroNode2(3, "张飞");
		HeroNode2 node4 = new HeroNode2(4, "吕布");
		HeroNode2 node5 = new HeroNode2(5, "貂蝉");
		
		//添加节点
		doubleLinkedListDemo.addHeroNode2(node1);
		doubleLinkedListDemo.addHeroNode2(node2);
		doubleLinkedListDemo.addHeroNode2(node3);
		doubleLinkedListDemo.addHeroNode2(node4);
		doubleLinkedListDemo.addHeroNode2(node5);
		doubleLinkedListDemo.showLinkedList(doubleLinkedListDemo.getHead());
		doubleLinkedListDemo.updataLinkedList(new HeroNode2(5, "夏侯惇"));
		System.out.println("修改后的链表");
		doubleLinkedListDemo.showLinkedList(doubleLinkedListDemo.getHead());
		//删除第五个
		doubleLinkedListDemo.delLinkedList(5);
		System.out.println("显示删除后的链表");
		doubleLinkedListDemo.showLinkedList(doubleLinkedListDemo.getHead());
	}
}



class DoubleLinkedListDemo{
private HeroNode2 head = new HeroNode2(0, "");
	
	//头结点是为了方便查找,此方法用来获取头结点
	public HeroNode2 getHead() {
		return head;
	}
	
	//添加节点
	public void addHeroNode2(HeroNode2 heroNode) {
		//因为head节点是不能动的,因此我们需要一个辅助节点temp
		HeroNode2 temp = head;
		//添加数据是从链表的最后添加;
		//如何确认最后的位置,只能     节点.next 这样遍历下去,直到值为null则说明找到了最后的位置
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		temp.next = heroNode;		//将新节点添加进去即可
		heroNode.prev = temp;
	}
	
	
	
	//显示链表
	public void showLinkedList(HeroNode2 head) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		
		//因为头结点是不能动的,所以需要一个辅助变量来遍历
		HeroNode2 temp = head.next;
		
		while(true) {
			if(temp == null)
				break;
			//System.out.println(temp.prev);		//打印前驱
			System.out.println(temp);
			//System.out.println(temp.next);		//打印后继
			//System.out.println("----------------------");
			temp = temp.next;
		}
	}
	
	
	//1.刘备  2.关羽   3.张飞
	//if(temp.id = hearoNode.id) temp.name = heroNode.name
	//修改链表节点数据
	public void updataLinkedList(HeroNode2 heroNode) {
		//判断链表是否为空
		if(head.next == null) {
			System.out.println("链表为空");
			return;
		}
		//定义一个辅助节点
		HeroNode2 temp = head.next;
		boolean flag = false;
		//是否找到对应节点
		while(true) {
			//如果找到
			if(temp.id == heroNode.id) {
				flag = true;
				break;
			}
			//防止空指针报错
			if(temp.next == null) {
				break;
			}
			temp = temp.next;		//temp后移
		}
		
		if(flag) {
			temp.name = heroNode.name;		//将你传入的节点值赋值到原来的节点里面,实现修改
		}else {
			System.out.println("没有找到id为" + heroNode.id);
		}
	}
	
	
	
	
	//删除节点
	public void delLinkedList(int id) {
		HeroNode2 temp = head.next;
		boolean flag = false;
		//找到待删除节点的前一个节点
		while(true) {
			//找到
			if(temp.id == id) {
				flag = true;
				break;
			}
			//已经遍历到最后,需要跳出循环
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			//next是下一个,而next.next就是下下个,实现跳过中间的(删除)
			//temp.next = temp.next.next;
			temp.prev.next = temp.next;
			//避免空指针
			if(temp.next != null) {
				temp.next.prev = temp.prev;
			}
		}else {
			System.out.println("没有找到id为" + id);
		}
	}
	
	
	//编号排序插入
	public void addReorder(HeroNode2 heroNode) {
		HeroNode2 temp = head;
		//创建临时辅助指针
		HeroNode2 current = new HeroNode2(0, "");
		boolean flag = false;
		while(true) {
			//链表到最后
			if(temp.next == null) {
				flag = true;
				break;
			}else if (temp.next.id > heroNode.id) {
				flag = true;
				break;
			}else if (temp.next.id == heroNode.id) {
				break;
			}
			temp = temp.next;
		}
		if(flag) {
			if(temp.next != null) {
				heroNode.next = temp.next;
				temp.next = heroNode;
				heroNode.prev = temp;
				heroNode.next.prev = heroNode;
				
				//利用中间辅助指针(第二种方法)
				/*current.next = temp.next;
				temp.next = heroNode;
				heroNode.prev = temp;
				heroNode.next = current.next;
				current.next.prev = heroNode;*/
			}
		}else {
			//id重复
			System.out.println("id" + heroNode.id + "重复");
		}
	}
}


//相当于一个节点
class HeroNode2{
	public int id;
	public String name;
	public HeroNode2 next;		//用来指向下一个节点
	public HeroNode2 prev;		//用来指向第一个节点
	
	public HeroNode2(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "HeroNode [id=" + id + ", name=" + name + "]";
	}
	
}

7.环状链表解决约瑟夫问题:

有i个小孩,从第k个小孩开始报数,每报数m次,那个小孩出列,然后从出列小孩的下一个继续报数,直到所有人出列,我们需要知道的是出列的顺序(例如:有五个小孩,从第一个小孩开始报数,每报数三次,那么第一个小孩报,第二个小孩报2,第三个小孩报3,第三个小孩出列;此时链表剩余小孩为:1,2,4,5;然后从第四个小孩继续报数,再次报三个,那么第四个小孩报1,第五个小孩报2,再到第一个小孩报3,那么第一个小孩出列,一直循环到结束。)

package com.mrz.test;

/*
 * 2022-04-28
 * mrz
 * 环状链表解决约瑟夫问题
 */
public class JosephLinkedList {
	public static void main(String[] args) {
		CicrleSingList list = new CicrleSingList();		//创建环形链表
		list.addBoy(5);
		list.countBoy(1,3,5);		//从第几个小孩开始报数,每次报数几下,圈中原本有多少个小孩
	}
}

class CicrleSingList{
	Boy first = null;


public void addBoy(int num) {
	Boy cur = null;
	for(int i = 1; i <= num; i++) {
		Boy boy = new Boy(i);
		if(i == 1) {
			first = boy;
			boy.setNext(first);
			cur = boy;
		}else {
			cur.setNext(boy);
			boy.setNext(first);
			cur = boy;
		}
	}
}


public void showBoy() {
	Boy cur = first;
	while(true) {
		if(cur.getNext() == first) {
			System.out.print("done");
			break;
		}
		System.out.println(cur);
		cur = cur.getNext();
	}
	}


/**
 * 
 * @param start 从第几个小孩开始报数
 * @param count 每次报数喊几下
 * @param nums 圈中原本有多少小孩
 *
 */
public void countBoy(int start,int count,int nums) {
	if(first == null || count < 1 || count > nums) {
		System.out.println("wrong");
		return;
	}
	Boy helper = first;		//帮助我们进行小孩出列操作
	while(true) {			//将helper指针移到了链表的最后
		if(helper.getNext() == first) {
			break;
		}
		helper = helper.getNext();
	}
	
	//如何完成从第几(start)个小孩开始报数
	for(int i = 0;i < start - 1;i++) {
		first = first.getNext();
		helper = helper.getNext();
	}
	
	//报数,然后移出队列
	while(true) {
		if(helper == first) {		//说明圈中只剩下一个小孩
			System.out.printf("最后小孩编号=%d\n",first.getNo());
			break;
		}
		
		for(int i = 0;i < count - 1;i++) {		//小孩开始报数   假设需要喊三次
			//后移两次,因为每个小孩本身需要报数一次,所以是用count-1
			first = first.getNext();
			helper = helper.getNext();
		}
		System.out.printf("小孩出圈,编号=%d\n",first.getNo());
		first = first.getNext();
		helper.setNext(first);
	}
	System.out.println("所有小孩出圈");
	
}


}






class Boy{
	private int no;
	private Boy next;
	
	
	
	public Boy(int no) {
		super();
		this.no = no;
	}
	
	public Boy() {
		super();
	}
	
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Boy getNext() {
		return next;
	}
	public void setNext(Boy next) {
		this.next = next;
	}
	
	@Override
	public String toString() {
		return "Boy [no=" + no + "]";
	}
	
	
}

如果不明白的话可以参考学习视频【十分钟算法-图解】环形链表-约瑟夫问题_哔哩哔哩_bilibili

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是C语言链表基本操作的代码示例: ```c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node *next; }; struct Node* create_node(int data) { struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); new_node->data = data; new_node->next = NULL; return new_node; } void add_node(struct Node** head, int data) { struct Node* new_node = create_node(data); if (*head == NULL) { *head = new_node; return; } struct Node* current_node = *head; while (current_node->next != NULL) { current_node = current_node->next; } current_node->next = new_node; } void delete_node(struct Node** head, int data) { struct Node* current_node = *head; struct Node* prev_node = NULL; while (current_node != NULL && current_node->data != data) { prev_node = current_node; current_node = current_node->next; } if (current_node == NULL) { return; } if (prev_node == NULL) { *head = current_node->next; } else { prev_node->next = current_node->next; } free(current_node); } void print_list(struct Node* head) { struct Node* current_node = head; while (current_node != NULL) { printf("%d ", current_node->data); current_node = current_node->next; } printf("\n"); } int main() { struct Node* head = NULL; add_node(&head, 5); add_node(&head, 10); add_node(&head, 15); add_node(&head, 20); print_list(head); delete_node(&head, 15); print_list(head); delete_node(&head, 5); print_list(head); return 0; } ``` 以上是一个简单的链表实现,包括了节点创建、添加、删除以及遍历链表并打印数据的操作。请注意,这只是一个示例代码,实际应用时需要根据具体问题进行适当的修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值