• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
百事可爱
一起努力鸭~~~
博客园    首页    新随笔    联系   管理    订阅  订阅
单链表

单链表

先说一下在C语言中的链表:

  1. 每个节点包含两个域,存数据元素信息的叫数据域(data域),存储直接后继(下一个节点)的存储位置的叫指针域(next域)
  2. 首元结点是指表中存储第一个数据的结点,头结点(head)是在首元结点之前附设的一个结点,其指针域指向首元结点;头指针是指向链表中第一个结点的指针,若有头结点,则头指针就指向头结点,否则指向首元结点;
  3. 最后一个结点没有直接后继,指针域为null

类比去学习
在java中:(虽无指针,在java 指针即是引用)

  1. 基本单元是节点Node,每个节点都有两个属性:存储的数据和下一个节点的内存地址,即data域和next域,也会有头结点head, 不放数据,作用就是表头,专门用于存放首元结点的内存位置
  2. 最后一个结点没有直接后继,(指针域)为null,链表分有无头结点的
  3. 整个链表的存取都是要从头结点开始进行

增删改查

1. 链表结点的添加(创建)和遍历,修改

对于创建链表:

  1. 先创建一个head头结点,作用就表示点链表的头
  2. 后面每添加一个结点,就直接加入到链表的最后(需要遍历找到)
    遍历:
    通过一个辅助变量帮助遍历整个链表
    3.要添加到指定位置时:
    首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
    新结点的next = temp.next(保证新节点连上它后面的结点)
    temp.next = 新结点(保证新节点连上它前面的结点)

应用实例:

使用带头结点的单链表实现:水浒英雄排行榜的管理

  1. 在添加英雄时,直接添加到链表的尾部

public class Test {

	public static void main(String[] args) {
		 //创建结点
		HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
		HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
		HeroNode hero3 = new HeroNode(3,"吴用","智多星");
		HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
		
		//创建链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		//将结点添加到链表
		singleLinkedList.add(hero1);
		singleLinkedList.add(hero2);
		singleLinkedList.add(hero3);
		singleLinkedList.add(hero4);
		//显示链表的内容
		singleLinkedList.list();
	}

}

//定义HeroNode,每个HeroNode对象就是一个结点
class HeroNode{
	public int no;//名次
	public String name;
	public String nickname;//别名
	public HeroNode next;//指向下一个结点
	
	//构造器
	public HeroNode(int no, String name, String nickname) {
		 
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//重写toString方法
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}	
}

//创建单链表,管理英雄对象
class SingleLinkedList{
	//先初始化一个头结点,头结点不要动,不存放具体的数据
	private HeroNode head = new HeroNode(0, "", "");
	
	//添加结点到单链表
	//要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
	public void add(HeroNode heroNode) {//参数就是一个结点	
		//1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
		
		HeroNode temp = head;//此时temp指向头结点
		//2. 遍历链表
		while(true) {
			if(temp.next == null) {//此时找到链表的最后
				break;
			}
			//如果没有找到链表的最后,就将temp后移
			temp = temp.next;
		}
		
		//3. 当退出while循环后,temp就指向了链表的最后
		temp.next  = heroNode;//让最后的结点的next域指向要添加的新结点
	}
	
	//显示链表(遍历)
	public void list() {
		//1.先判断链表是否为空
		if(head.next == null) { 
				System.out.println("说明链表为空");
				return;
		}
		//2. 借助一个辅助变量temp帮助遍历整个链表
		HeroNode temp = head.next;//此时temp指向首元结点
		while(true) {
			if(temp == null) {//此时找到链表的最后
				break;
			}
			//输出结点的信息
			System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
			//将temp后移
			temp = temp.next;
		}
	}	
}
  1. 在添加英雄时,根据排名将英雄插入到指定位置(若已经有了这个排名,则提娜佳失败,并给出提示)

public class Test {

	public static void main(String[] args) {
		 //创建结点
		HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
		HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
		HeroNode hero3 = new HeroNode(3,"吴用","智多星");
		HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
		
		//创建链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		//将结点添加到链表
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		singleLinkedList.addByOrder(hero4);
		//显示链表的内容
		singleLinkedList.list();
	}

}

//定义HeroNode,每个HeroNode对象就是一个结点
class HeroNode{
	public int no;//名次
	public String name;
	public String nickname;//别名
	public HeroNode next;//指向下一个结点
	
	//构造器
	public HeroNode(int no, String name, String nickname) {
		 
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//重写toString方法
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}	
}

//创建单链表,管理英雄对象
class SingleLinkedList{
	//先初始化一个头结点,头结点不要动,不存放具体的数据
	private HeroNode head = new HeroNode(0, "", "");
	
//	//添加结点到单链表
//	//要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
//	public void add(HeroNode heroNode) {//参数就是一个结点	
//		//1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//		
//		HeroNode temp = head;//此时temp指向头结点
//		//2. 遍历链表
//		while(true) {
//			if(temp.next == null) {//此时找到链表的最后
//				break;
//			}
//			//如果没有找到链表的最后,就将temp后移
//			temp = temp.next;
//		}
//		
//		//3. 当退出while循环后,temp就指向了链表的最后
//		temp.next  = heroNode;//让最后的结点的next域指向要添加的新结点
//	}
	
	
	//3.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)
	public void addByOrder(HeroNode heroNode) {
		
     //1.	首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
		HeroNode temp = head; 
		boolean flag = false;//标识添加的编号是否存在,默认不存在
		while(true) {
			if(temp.next==null) {//说明temp已经在链表的最后
				break;
			}
			if(temp.next.no>heroNode.no) {//位置找到,就在temp的后面插入
				break;
			}
			else if(temp.next.no == heroNode.no) {//说明要添加的heroNode结点的编号已经存在
				flag = true;
				break;
			}
			//以上都没找到,直接让temp向后移动
			temp = temp.next;
		}
		
		//退出循环,判断flag的值
		if(flag) {
			System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n"+heroNode.no);
		}
		else {
			//插入到链表中,即temp的后面
//			新结点的next = temp.next(保证新节点连上它后面的结点)
//			temp.next = 新结点(保证新节点连上它前面的结点)
			heroNode.next = temp.next;
			temp.next = heroNode;
		}
		
		
	}
    
	//显示链表(遍历)
	public void list() {
		//1.先判断链表是否为空
		if(head.next == null) { 
				System.out.println("说明链表为空");
				return;
		}
		//2. 借助一个辅助变量temp帮助遍历整个链表
		HeroNode temp = head.next;//此时temp指向首元结点
		while(true) {
			if(temp == null) {//此时找到链表的最后
				break;
			}
			//输出结点的信息
			System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
			//将temp后移
			temp = temp.next;
		}
	}
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
}

2. 链表结点的修改

  1. 英雄编号不变,修改其他属性值
//四.修改结点(英雄编号不变,修改其他属性值)
	//根据no编号来修改,no编号不变
	public void update(HeroNode newNode) {
		//判断是否为空
		if(head.next==null) {
			System.out.println("链表为空");
			return;
		}
		//根据no编号找到需要修改的结点
		//借助辅助变量
		HeroNode temp =head.next;
		boolean flag = false;//标识是否找到改结点
		while(true) {
			if(temp==null) {//说明temp已经在链表的最后
				break;
			}
			if(temp.no==newNode.no) {//说明已经找到了
				flag = true;
				break;
			}
			//最重要的,不要忘记让temp后移,才能遍历
			temp = temp.next;
		}
		
		//根据flag来判断是否找到要修改的结点
		if(flag) {
			temp.name = newNode.name;
			temp.nickname  = newNode.nickname;
		}
		else {
			//没有找到
			System.out.println("未找到编号为 %d 的结点,不能修改\n"+newNode.no);
		}
		
	}

3. 链表结点的删除

  1. 借助辅助变量找到需要删除的结点的前一个结点
  2. temp.next = temp.next.next;

public class Test {

	public static void main(String[] args) {
		 //创建结点
		HeroNode hero1 = new HeroNode(1,"宋江","及时雨");
		HeroNode hero2 = new HeroNode(2,"卢俊义","玉麒麟");
		HeroNode hero3 = new HeroNode(3,"吴用","智多星");
		HeroNode hero4 = new HeroNode(4,"林冲","豹子头");
		
		//创建链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		//将结点添加到链表
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		singleLinkedList.addByOrder(hero4);
		
		//显示链表的内容
				singleLinkedList.list();
		
		//测试修改结点
		HeroNode newNode = new HeroNode(2,"卢俊义yaya","玉麒麟yayaya");
		singleLinkedList.update(newNode);
		System.out.println("修改后的结果-----------");
		//显示链表的内容
		singleLinkedList.list();
		
		//删除一个节点
		singleLinkedList.del(1);
		System.out.println("删除结点后的结果-----------");
		singleLinkedList.list();
	}

}

//定义HeroNode,每个HeroNode对象就是一个结点
class HeroNode{
	public int no;//名次
	public String name;
	public String nickname;//别名
	public HeroNode next;//指向下一个结点
	
	//构造器
	public HeroNode(int no, String name, String nickname) {
		 
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//重写toString方法
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}	
}

//创建单链表,管理英雄对象
class SingleLinkedList{
	//先初始化一个头结点,头结点不要动,不存放具体的数据
	private HeroNode head = new HeroNode(0, "", "");
	
//	//一.  添加结点到单链表--------------------------
//	//要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
//	public void add(HeroNode heroNode) {//参数就是一个结点	
//		//1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//		
//		HeroNode temp = head;//此时temp指向头结点
//		//2. 遍历链表
//		while(true) {
//			if(temp.next == null) {//此时找到链表的最后
//				break;
//			}
//			//如果没有找到链表的最后,就将temp后移
//			temp = temp.next;
//		}
//		
//		//3. 当退出while循环后,temp就指向了链表的最后
//		temp.next  = heroNode;//让最后的结点的next域指向要添加的新结点
//	}
	
	//三.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)----------------
	public void addByOrder(HeroNode heroNode) {
		
     //1.	首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
		HeroNode temp = head; 
		boolean flag = false;//标识添加的编号是否存在,默认不存在
		while(true) {
			if(temp.next==null) {//说明temp已经在链表的最后
				break;
			}
			if(temp.next.no>heroNode.no) {//位置找到,就在temp的后面插入
				break;
			}
			else if(temp.next.no == heroNode.no) {//说明要添加的heroNode结点的编号已经存在
				flag = true;
				break;
			}
			//以上都没找到,直接让temp向后移动
			temp = temp.next;
		}
		
		//退出循环,判断flag的值
		if(flag) {
			System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n"+heroNode.no);
		}
		else {
			//插入到链表中,即temp的后面
//			新结点的next = temp.next(保证新节点连上它后面的结点)
//			temp.next = 新结点(保证新节点连上它前面的结点)
			heroNode.next = temp.next;
			temp.next = heroNode;
		}	
		
	}
	//四.修改结点(英雄编号不变,修改其他属性值)
	//根据no编号来修改,no编号不变
	public void update(HeroNode newNode) {
		//判断是否为空
		if(head.next==null) {
			System.out.println("链表为空");
			return;
		}
		//根据no编号找到需要修改的结点
		//借助辅助变量
		HeroNode temp =head.next;
		boolean flag = false;//标识是否找到改结点
		while(true) {
			if(temp==null) {//说明temp已经在链表的最后
				break;
			}
			if(temp.no==newNode.no) {//说明已经找到了
				flag = true;
				break;
			}
			//最重要的,不要忘记让temp后移,才能遍历
			temp = temp.next;
		}
		
		//根据flag来判断是否找到要修改的结点
		if(flag) {
			temp.name = newNode.name;
			temp.nickname  = newNode.nickname;
		}
		else {
			//没有找到
			System.out.println("未找到编号为 %d 的结点,不能修改\n"+newNode.no);
		}
		
	}
	
	//五. 删除结点
//	1. 借助辅助变量找到需要删除的结点的前一个结点
//	2. temp.next =  temp.next.next;
	
	public void del(int no) {
		HeroNode temp =head;
		boolean flag = false;//标识是否找到待删除结点的前一个结点
		while(true) {
			if(temp.next == null) {//说明temp已经在链表的最后
				break;
			}
			//在比较时,是temp.next.no 和 需要删除结点的no进行比较
			if(temp.next.no == no) {
				flag = true;
				break;
			}
			temp = temp.next;
		}
		
		if(flag) {
			temp.next =  temp.next.next;
		}
		else {
			//没有找到
			System.out.println("未找到编号为 %d 的结点,不存在\n"+no);
		}
	}
	
	//二.显示链表(遍历)-----------------------
	public void list() {
		//1.先判断链表是否为空
		if(head.next == null) { 
				System.out.println("说明链表为空");
				return;
		}
		//2. 借助一个辅助变量temp帮助遍历整个链表
		HeroNode temp = head.next;//此时temp指向首元结点
		while(true) {
			if(temp == null) {//此时找到链表的最后
				break;
			}
			//输出结点的信息
			System.out.println(temp);//因为已经重写了toString 方法直接输出引用,会默认调用此方法
			//将temp后移
			temp = temp.next;
		}
	}
输出结果:
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
修改后的结果-----------
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
删除结点后的结果-----------
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
	
}

一些应用:

1. 统计有效结点的个数(若是带头结点,需求不统计头结点),考遍历

// 六,统计有效结点的个数(遍历)
	public static int getLength(HeroNode head) {// 其中head指 链表的头结点
		if (head.next == null) {// 空链表
			return 0;
		}
		int length = 0;
		HeroNode temp = head.next;
		while (temp != null) {
			length++;
			temp = temp.next;
		}
		return length;
	}

2.查找单链表中的倒数第K个结点

//七.查找单链表中的倒数第K个结点
//	思路:
//	编写一个方法,接收一个头结点,还要接收一个k,表示倒数第K个结点
//  先把链表从头到尾遍历,得到链表的总的长度length,调用getLength()方法
//  再从链表的第一个结点开始遍历(length-k)个,找到就返回该结点,否则返回null
	
	public static HeroNode find(HeroNode head,int k) {
		if (head.next == null) {// 空链表
			return null;
		}
		int length = getLength(head);
		//第二次遍历length-k个,即为倒数第K个结点
		//先对k做一下校验
		if(k<=0 || k>length) {
			return null;
		}
		
		HeroNode temp = head.next;
		//for循环定位到倒数第k位
		for(int i=0;i<length-k;i++) {
			temp = temp.next;
		}
		return temp;
	}

3.单链表的反转

思路:

  1. 先新建一个头结点newhead
  2. 从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面,(注意:是每取出一个就放置在紧邻着newhead的后面)
  3. 最后取完所有原来的结点后,让原来链表的头结点.next = newhead.next
//八.单链表的反转
	public static void reverseList(HeroNode head) {
		//如果当前链表为空或者只有一个结点,无需反转,直接返回
		if(head.next==null || head.next.next==null) {
			return;
		}
		//定义一个辅助指针(变量)来遍历原来链表
		HeroNode cur  = head.next;//指向当前结点
		HeroNode next  = null;//指向当前结点cur的下一个结点,因为cur指向的结点要被取走,若没有记录被取走结点的下一个结点,链表断开
		HeroNode newhead  = new HeroNode(0,"","");//新的头结点
		//从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面
		while(cur!=null) {
			next = cur.next;//先保存cur的下一个结点的位置,再将此结点取出
			cur.next = newhead.next;//将cur的下一个结点指向新的链表的最前端
			newhead.next = cur;//链接上新链表
			cur = next;//cur实现后移
			
			//以上过程画图就明白了
		}
		head.next = newhead.next;	
	}

再次汇总代码:

 

public class Test {

	public static void main(String[] args) {
		// 创建结点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");

		// 创建链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		// 将结点添加到链表
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		singleLinkedList.addByOrder(hero4);

		// 显示链表的内容
		singleLinkedList.list();

		// 测试修改结点
		HeroNode newNode = new HeroNode(2, "卢俊义yaya", "玉麒麟yayaya");
		singleLinkedList.update(newNode);
		System.out.println("修改后的结果-----------");
		// 显示链表的内容
		singleLinkedList.list();

		// 删除一个节点
		singleLinkedList.del(1);
		System.out.println("删除结点后的结果-----------");
		singleLinkedList.list();

		// 统计有效结点的个数
		// 因为头结点设为私有的,所以添加了get方法来获得
		System.out.println("有效的结点个数:"+SingleLinkedList.getLength(singleLinkedList.getHead()));
		
		//测试查找单链表中的倒数第1个结点
		HeroNode reHeroNode = SingleLinkedList.find(singleLinkedList.getHead(),1);
		System.out.println("倒数第1个结点是"+reHeroNode);
		
		//测试反转
		System.out.println("反转后的链表:");
		SingleLinkedList.reverseList(singleLinkedList.getHead());
		singleLinkedList.list();
	}

}

//定义HeroNode,每个HeroNode对象就是一个结点
class HeroNode {
	public int no;// 名次
	public String name;
	public String nickname;// 别名
	public HeroNode next;// 指向下一个结点

	// 构造器
	public HeroNode(int no, String name, String nickname) {

		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	// 重写toString方法
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
}

//创建单链表,管理英雄对象
class SingleLinkedList {
	// 先初始化一个头结点,头结点不要动,不存放具体的数据
	private HeroNode head = new HeroNode(0, "", "");
	public HeroNode getHead() {
		return head;
	}

	public void setHead(HeroNode head) {
		this.head = head;
	}


//	//一.  添加结点到单链表--------------------------
//	//要先找到链表最后的结点,让最后的结点的next域指向要添加的新结点
//	public void add(HeroNode heroNode) {//参数就是一个结点	
//		//1. 因为head结点不能动,要借助一个辅助变量temp帮助遍历整个链表
//		
//		HeroNode temp = head;//此时temp指向头结点
//		//2. 遍历链表
//		while(true) {
//			if(temp.next == null) {//此时找到链表的最后
//				break;
//			}
//			//如果没有找到链表的最后,就将temp后移
//			temp = temp.next;
//		}
//		
//		//3. 当退出while循环后,temp就指向了链表的最后
//		temp.next  = heroNode;//让最后的结点的next域指向要添加的新结点
//	}

	
	// 三.结点要添加到指定位置时:(此处排名有顺序要求,按编号的大小)----------------
	public void addByOrder(HeroNode heroNode) {

		// 1. 首先找到新添加结点的位置的前一个结点,并让辅助结点temp指向此结点
		HeroNode temp = head;
		boolean flag = false;// 标识添加的编号是否存在,默认不存在
		while (true) {
			if (temp.next == null) {// 说明temp已经在链表的最后
				break;
			}
			if (temp.next.no > heroNode.no) {// 位置找到,就在temp的后面插入
				break;
			} else if (temp.next.no == heroNode.no) {// 说明要添加的heroNode结点的编号已经存在
				flag = true;
				break;
			}
			// 以上都没找到,直接让temp向后移动
			temp = temp.next;
		}

		// 退出循环,判断flag的值
		if (flag) {
			System.out.print("准备插入的英雄的编号%d 已经存在,不能加入\n" + heroNode.no);
		} else {
			// 插入到链表中,即temp的后面
//			新结点的next = temp.next(保证新节点连上它后面的结点)
//			temp.next = 新结点(保证新节点连上它前面的结点)
			heroNode.next = temp.next;
			temp.next = heroNode;
		}

	}

	// 四.修改结点(英雄编号不变,修改其他属性值)
	// 根据no编号来修改,no编号不变
	public void update(HeroNode newNode) {
		// 判断是否为空
		if (head.next == null) {
			System.out.println("链表为空");
			return;
		}
		// 根据no编号找到需要修改的结点
		// 借助辅助变量
		HeroNode temp = head.next;
		boolean flag = false;// 标识是否找到改结点
		while (true) {
			if (temp == null) {// 说明temp已经在链表的最后
				break;
			}
			if (temp.no == newNode.no) {// 说明已经找到了
				flag = true;
				break;
			}
			// 最重要的,不要忘记让temp后移,才能遍历
			temp = temp.next;
		}

		// 根据flag来判断是否找到要修改的结点
		if (flag) {
			temp.name = newNode.name;
			temp.nickname = newNode.nickname;
		} else {
			// 没有找到
			System.out.println("未找到编号为 %d 的结点,不能修改\n" + newNode.no);
		}

	}

	// 五. 删除结点
//	1. 借助辅助变量找到需要删除的结点的前一个结点
//	2. temp.next =  temp.next.next;

	public void del(int no) {
		HeroNode temp = head;
		boolean flag = false;// 标识是否找到待删除结点的前一个结点
		while (true) {
			if (temp.next == null) {// 说明temp已经在链表的最后
				break;
			}
			// 在比较时,是temp.next.no 和 需要删除结点的no进行比较
			if (temp.next.no == no) {
				flag = true;
				break;
			}
			temp = temp.next;
		}

		if (flag) {
			temp.next = temp.next.next;
		} else {
			// 没有找到
			System.out.println("未找到编号为 %d 的结点,不存在\n" + no);
		}
	}
	// --------------------------------------------------

	// 六,统计有效结点的个数(遍历)
	public static int getLength(HeroNode head) {// 其中head指 链表的头结点
		if (head.next == null) {// 空链表
			return 0;
		}
		int length = 0;
		HeroNode temp = head.next;
		while (temp != null) {
			length++;
			temp = temp.next;
		}
		return length;
	}
	
	//七.查找单链表中的倒数第K个结点
//	思路:
//	编写一个方法,接收一个头结点,还要接收一个k,表示倒数第K个结点
//  先把链表从头到尾遍历,得到链表的总的长度length,调用getLength()方法
//  再从链表的第一个结点开始遍历(length-k)个,找到就返回该结点,否则返回null
	
	public static HeroNode find(HeroNode head,int k) {
		if (head.next == null) {// 空链表
			return null;
		}
		int length = getLength(head);
		//第二次遍历length-k个,即为倒数第K个结点
		//先对k做一下校验
		if(k<=0 || k>length) {
			return null;
		}
		
		HeroNode temp = head.next;
		//for循环定位到倒数第k位
		for(int i=0;i<length-k;i++) {
			temp = temp.next;
		}
		return temp;
	}
	
	
	//八.单链表的反转
	public static void reverseList(HeroNode head) {
		//如果当前链表为空或者只有一个结点,无需反转,直接返回
		if(head.next==null || head.next.next==null) {
			return;
		}
		//定义一个辅助指针(变量)来遍历原来链表
		HeroNode cur  = head.next;//指向当前结点
		HeroNode next  = null;//指向当前结点cur的下一个结点,因为cur指向的结点要被取走,若没有记录被取走结点的下一个结点,链表断开
		HeroNode newhead  = new HeroNode(0,"","");//新的头结点
		//从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表的头结点newhead的后面
		while(cur!=null) {
			next = cur.next;//先保存cur的下一个结点的位置,再将此结点取出
			cur.next = newhead.next;//将cur的下一个结点指向新的链表的最前端
			newhead.next = cur;//链接上新链表
			cur = next;//cur实现后移
			
			//以上过程画图就明白了
		}
		head.next = newhead.next;	
	}

	
	// 二.显示链表(遍历)-----------------------
	public void list() {
		// 1.先判断链表是否为空
		if (head.next == null) {
			System.out.println("说明链表为空");
			return;
		}
		// 2. 借助一个辅助变量temp帮助遍历整个链表
		HeroNode temp = head.next;// 此时temp指向首元结点
		while (true) {
			if (temp == null) {// 此时找到链表的最后
				break;
			}
			// 输出结点的信息
			System.out.println(temp);// 因为已经重写了toString 方法直接输出引用,会默认调用此方法
			// 将temp后移
			temp = temp.next;
		}
	}
输出结果:
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义, nickname=玉麒麟]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
修改后的结果-----------
HeroNode [no=1, name=宋江, nickname=及时雨]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
删除结点后的结果-----------
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=4, name=林冲, nickname=豹子头]
有效的结点个数:3
倒数第1个结点是HeroNode [no=4, name=林冲, nickname=豹子头]
反转后的链表:
HeroNode [no=4, name=林冲, nickname=豹子头]
HeroNode [no=3, name=吴用, nickname=智多星]
HeroNode [no=2, name=卢俊义yaya, nickname=玉麒麟yayaya]

}
posted on 2022-03-03 19:30  精致猪猪侠  阅读(124)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3