c++ 链表_Java数据结构——链表(用Java实现C语言的指针,思想)

一 . 链表的概述

1.1 链式存储:

用一组任意类型的存储单元存储线性表,在逻辑上面相邻的结点在物理位置上面不一定相邻。

1.2 链表:

采用链式存储方法的线性表叫做链表

1.3 链表的特点:

其结点的存储单元可以不连续,每个结点中除存储原表结点中的数据外,还须存储指示其直接后继或前趋结点的地址,以反映结点之间的逻辑关系。因此,链表中每个结点由两部分构成:数据域和链域

链表没有固定的长度,可以在后面一直加

1.4 链表的分类

从实现角度可分为:动态链表和静态链表

从链接方式可分为:单链表、双链表和循环链表

二 . 单链表

指的是单向链表,每个节点的结构如下:

17cbed7b9fb80ae79c7ae1ba09337fed.png

把结点的实现,用面向对象的方法分析,把结点归为一个Structural类。

Structural类中把数据域和后继节点都转为类的属性。

cd13b0c7c113702e35a4f565a405664f.png

通常,我们定义一个链表,在他的第一个元素都不存储东西,让他只作为一个head标记,具体原因为什么?

因为链表有删除操作,如果要删除的是第一个结点,我们没有最前面head结点的话,就没有办法进行。

比如,数据域我们就存储一个name。

那么Node类的结构如下:

public class Structural {
	public String name;
	public Structural next;
}

我们可以把创建节点,分配空间的过程,在构造方法中完成

// 创建节点,分配空间
	public Structural(String name, Structural next) {
		// TODO Auto-generated constructor stub
		this.name = name;
		this.next = next;
	}

这样我们利用类的构造方法就可以完成,结点的创建过程。

因为链表最小单元,就是一个结点,我们就把链表的操作归给,这个结点的方法,写出静态方法,调用的时候,只需要直接用类名调用就行。

一个结点就是一个链表,如需加入更多结点只需要在后面接着加就好了!!!

下来开始写链表的操作:

(1)插入操作

2e5ad47160a3b725f615279d1dfebd6e.png

e8581a82c367c4dcb24c8114d1ace8d0.png
// 插入操作(链表头节点,一个指定节点,要插入的节点) 插到指定节点之后
	public static void insert(Structural head, Structural index, Structural data) {
		boolean flag = false;
		// 如果头指针不存在,链表不存在
		if (head == null) {
			return;
		}
		// 如果插入到头节点之后,也就是要成为第一个元素
		if (head.next == index) {
			data.next = head.next;
			head.next = data;
			flag = true;
		}

		while (head.next != null) {
			head = head.next;
			if (head == index) {
				data.next = head.next;
				head.next = data;
				flag = true;

				break;
			}

		}
		if (flag == true) {
			System.out.println("插入成功");
		} else {
			System.out.println("插入失败");
		}

	}

(2)删除操作

f5a5ef12429304463726bc15e555b514.png

代码实现:

	// 删除操作(头节点,要删除节点)
	public static void dir(Structural head, Structural data) {
		boolean flag = false;
		// 如果头指针不存在,链表不存在
		if (head == null) {
			System.out.println("删除失败");
			return;
		}
		// 如果删除头节点
		if (head == data) {
			head = head.next;
			flag = true;
		}
		while (head.next != null) {
			if (head.next == data) {
				head.next = head.next.next;
				flag = true;
				break;
			}
			head = head.next;
		}
		if (flag) {
			System.out.println("删除成功");
		} else {
			System.out.println("删除失败");
		}
	}

(3) 修改操作

b23d5bf857825d3ef50167ee3b2fabbf.png

代码实现:

public static void revise(Structural head, Structural str1, Structural str2) {
		boolean flag = false;
		if (head == null) {
			System.out.println("修改失败");
		}

		while (head.next != null) {

			if (head.next == str1) {
				str2.next = head.next.next;
				head.next = str2;
				flag = true;
				break;
			}
			head = head.next;
		}
		if (flag) {
			System.out.println("修改成功");
		} else {
			System.out.println("修改失败");
		}

	}

测试:

public class LinkedList {
	public static void main(String[] args) {
		Structural head = new Structural(null, null);
		Structural structural1 = new Structural("a",null);
		Structural structural2 = new Structural("b",null);
		Structural structural3 = new Structural("c",null);
		Structural structural4 = new Structural("d",null);
		Structural structural5 = new Structural("e",null);
		
		//单向链表
		head.next = structural1;
		structural1.next = structural2;
		structural2.next = structural3;
		structural3.next = structural4;
		structural4.next = structural5;		
		
		
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		
		
		
		System.out.println("---------------------");
		//插入(把f插到d后面)
		Structural structural6 = new Structural("f", null);
		Structural.insert(head, structural4, structural6);
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		System.out.println("---------------------");
		//删除(把f删除)中间元素删除
		Structural.dir(head, structural6);
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		System.out.println("---------------------");
		//删除(把a删除)头节点删除
		Structural.dir(head, structural1);
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		System.out.println("---------------------");
		//删除(把e删除)末尾节点删除
		Structural.dir(head, structural5);
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		System.out.println("---------------------");
		
		//修改(把c改为g)
		Structural structural7 = new Structural("g", null);
		Structural.revise(head,structural3, structural7);
		for(Structural structural = head ; structural != null ;structural = structural.next) {
			System.out.println(structural);
		}
		System.out.println("---------------------");
		
			
	}
	
}

结果:+

Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
插入成功
Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=f]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=a]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=b]
Structural [name=c]
Structural [name=d]
Structural [name=e]
---------------------
删除成功
Structural [name=null]
Structural [name=b]
Structural [name=c]
Structural [name=d]
---------------------
修改成功
Structural [name=null]
Structural [name=b]
Structural [name=g]
Structural [name=d]
---------------------

终于无聊的把自己的思路说完了。

三 . 一道经典的算法题——判断单链表是否有环

先看看链表可能出现的情况,所有单链表无非三种情况

* 第一种:从头节点指向下个,一直指下去,最后一个结点的next指向null

* 第二种:从头节点指向下个,一直指下去,最后一个结点的next指向头节点,形成一个首尾相连的环链表

* 第三种:从头节点指向下个,一直指下去,最后一个结点的next指向局部节点,形成一个局部尾部有环的链表。

关于如何判断单链表是否有环,有三种解法:

(1)先定义1个结点,先让他等于头节点,然后向后遍历,遍历一次,和头节点对比一次,如果出现相同,说明链表有环,如果没有出现相等情况,则说明没有环。

但是这种算法只能处理,前两种情况,因此缺乏普遍性,不适用。

(2)遍历链表,每遍历一个,把他们的hashcode值,先和数组里面的比较,如果没有再存储到一个数组里,如果找到有重复的,就说明有环。

(3)算法效率最高的,定义两个指针,一个跑得快,一个跑得慢,有一天他两相遇了,说明有环

例子:两个人都沿着跑步,都向前跑,一个跑的快,一个跑得慢,有一天他两相遇了,说明跑道中有环。

代码实现:

public static boolean hasLoop(Structural head) {
		
		if(head == null) {
			return false;
		}
		//定义一个跑的快的,每次遍历两个节点
		Structural stru1 = head;
		
		//定义一个跑的慢的,每次遍历一个节点
		Structural stru2 = head;
		while(true) {
			//避免一开始就相遇,让跑的快的,先跑两步。
			stru1 = stru1.next.next;
			stru2 =stru2.next;
			if(stru1 == null) {
				System.out.println("链表没有环");
				return false;
			}
			if(stru2 == stru1) {
					System.out.println("链表有环");
					return true;
				}		
			}
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值