12-9java面向对象之链表操作

    链表属于数据结构中的基本操作。

链表是一种物存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。

使用链表结构可以克服 数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了 数组随机读取的优点,同时链表由于增加了结点的 指针域,空间开销比较大。在计算机科学中,链表作为一种基础的 数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个/或下一个节点的位置的链接("links")。链表最明显的好处就是,常规 数组排列关联项目的方式可能不同于这些数据项目在 记忆体磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。而链表是一种自我指示 数据类型,因为它包含指向另一个相同类型的 数据指针链接)。链表允许插入和移除表上任意位置上的 节点,但是不允许 随机存取。链表有很多种不同的类型: 单向链表双向链表以及 循环链表
链表相当于一个队伍,内部存储的是队伍的人员,通过next来指向下一个对象。

1.链表介绍

案例:火车头->A->B->C  用链表的方式进行实现
class Node				//建立节点类,节点中保存数据和下一个对象
{
	//封装属性
	private String data;	//建立数据,可以是任何数据类型
	private Node next;		//作为连接的下一个对象
	//构造方法
	public Node(String data)
	{
		this.data = data;
	}
	//属性的获取和设置方法
	public void setData(String data)
	{
		this.data = data;
	}
	public String getData()
	{
		return this.data;
	}
	public void setNext(Node next)
	{
		this.next = next;
	}
	public Node getNext()
	{
		return this.next;
	}
}
public class TestChain
{
	public static void main(String [] args)
	{
		//建立节点
		Node root = new Node("火车头");
		Node n1 = new Node("车厢A");
		Node n2 = new Node("车厢B");
		Node n3 = new Node("车厢C");
		//建立节点的关系
		root.setNext(n1);
		n1.setNext(n2);
		n2.setNext(n3);
		//打印出这种关系
		print(root);
	}
	public static void print(Node node)
	{
		if (node != null)				//如果该节点存在即打印
		{
			System.out.println(node.getData());
			if (node.getNext() != null)	//同时指向下一个节点
			{
				print(node.getNext());
			}
		}	
	}
}
结果
之前博客更新过程中,更多的是把简单代码贴上去,今后将增加这一个讲解的过程。
1.Node类是我们的目标,他相当于对车厢的归类。Node中包含两个部分,第一个就是data,他可以是任何的数据类型;第二个就是Node类的next,他表示该对象所连接的下一个对象。
2.封装我就不多说了,主要是属性data的封装,至于类,需要在程序中实例化。
3.getter和setter函数是所有类中必须存在的
4.主程序中,
//建立节点
Node root = new Node("火车头");
Node n1 = new Node("车厢A");
Node n2 = new Node("车厢B");
Node n3 = new Node("车厢C");
//建立节点的关系
root.setNext(n1);
n1.setNext(n2);
n2.setNext(n3);
首先,实例化节点,其中root代表的是根节点,非常关键;其次,建立节点的联系,通过类中的set来指明下一个连接的对象。最后,打印。这里强调一下打印函数。
public static void print(Node node)
{
if (node != null)//如果该节点存在即打印
{
System.out.println(node.getData());
if (node.getNext() != null)//同时指向下一个节点
{
print(node.getNext());
}
}
}
打印函数,传递的是对象node。首先,判断node是不是空,如果对象是空,则没有打印的必要;其次不为空则打印data数据,并且判断是否有下一个对象和他相连,有的话,递归调用,这时候的参数就是下一个对象,用getNext()获取。

2.单向链表的实现

上文更多的是手工排列,如何实现自动?
一个基本的链表操作如下:
1.增加数据,用户只关心数据是什么,不关心数据的保存
2.输出数据,有多少个数据,就全部输出,用户不关系如何找到
3.查找数据是否存在
4.删除
不管链表如何实现,都需要Node类进行支持。
class Node				//建立节点类,节点中保存数据和下一个对象
{
	//封装属性
	private String data;	//建立数据,可以是任何数据类型
	private Node next;		//作为连接的下一个对象
	//构造方法
	public Node(String data)
	{
		this.data = data;
	}
	//属性的获取和设置方法
	public void setData(String data)
	{
		this.data = data;
	}
	public String getData()
	{
		return this.data;
	}
	public void setNext(Node next)
	{
		this.next = next;
	}
	public Node getNext()
	{
		return this.next;
	}
}
Node 类不变,他本身作为数据的载体出现,应该有程序自己控制。 现在好比有了一些要插入的数据(一群人),应该有一个来发号命令,这个类定义为 Link 链表操作中的根节点最重要,就想找到队伍的对头一样。第一个保存的元素为根节点。

2.1增加数据以及打印

用户增加数据,不关心Node,只关心数据(属性)。用户通过方法增加数据,必须由程序将数据封装成节点,使用Node的构造方法实现,否则无法完成next的引用问题。 

在增加数据变为节点之后,首先判断该操作(link)是否有根节点,没有的话,就把增加的节点赋值到根节点,否则,节点自己动作,找到合适的位置。那么如何找到合适的位置呢?

首先,判断当前节点指向的next是否为空。空则表明新节点放在当前节点后面即可;否则,说明当前节点还指向下一个节点,用下一个节点来递归调用该方法。

案例:

class Node				//建立节点类,节点中保存数据和下一个对象
{
	//封装属性
	private String data;	//建立数据,可以是任何数据类型
	private Node next;		//作为连接的下一个对象
	//构造方法
	public Node(String data)
	{
		this.data = data;
	}
	//属性的获取和设置方法
	public void setData(String data)
	{
		this.data = data;
	}
	public String getData()
	{
		return this.data;
	}
	public void setNext(Node next)
	{
		this.next = next;
	}
	public Node getNext()
	{
		return this.next;
	}
	//新节点找到合适的位置
	public void addNode(Node newnode)
	{
		if (this.getNext() == null)			//当前节点指向空,则可以把新节点排在这
		{
			this.setNext(newnode);
		}else
		{
			this.getNext().addNode(newnode);
		}
	}
	public void printNode()
	{
		System.out.println(this.getData());		//输出当前的数据
		if (this.getNext() != null)				//还有下一个节点
		{
			this.getNext().printNode();
		}
	}
}
class Link			//链表操作类
{
	private Node root;	//定义根节点
	public void add(String data)			//增加数据,需要把数据变为节点
	{
		Node newnode = new Node(data);
		if (this.root == null)				//根节点为空
		{
			this.root = newnode;
		}else 
		{
			this.root.addNode(newnode);
		}
	}
	public void print()						//输出的全部数据
	{
		if (this.root != null)
		{
			this.root.printNode();
		}
	}
}
public class TestChain
{
	public static void main(String [] args)
	{
		Link link = new Link();
		String root = "火车头";
		String n1 = "车厢1";
		String n2 = "车厢2";
		String n3 = "车厢3";
		link.add(root);
		link.add(n1);
		link.add(n2);
		link.add(n3);
		link.print();
	}
}
结果:

解释:

public void add(String data)			//增加数据,需要把数据变为节点
	{
		Node newnode = new Node(data);
		if (this.root == null)				//根节点为空
		{
			this.root = newnode;
		}else 
		{
			this.root.addNode(newnode);
		}
	}

首先,Node newnode = new Node(data);把增加的属性封装为节点;其次判断this.root是否为空,如果根节点为空,新节点即为根节点;否则要调用Node类进行增加节点。

在Node类中,

if (this.getNext() == null)			//当前节点指向空,则可以把新节点排在这
		{
			this.setNext(newnode);
		}else
		{
			this.getNext().addNode(newnode);
		}
首先判断当前节点的指向是否为空,如果是空说明新加入的节点可以直接链接到当前节点;否则要用下一个节点再次递归调用这一函数,找到合适位置

以上的这一切都归功于this关键字的操作,this代表的当前对象,那个对象调用了方法this就代表他。

2.2数据查找操作

class Node				//建立节点类,节点中保存数据和下一个对象
{
	//封装属性
	private String data;	//建立数据,可以是任何数据类型
	private Node next;		//作为连接的下一个对象
	//构造方法
	public Node(String data)
	{
		this.data = data;
	}
	//属性的获取和设置方法
	public void setData(String data)
	{
		this.data = data;
	}
	public String getData()
	{
		return this.data;
	}
	public void setNext(Node next)
	{
		this.next = next;
	}
	public Node getNext()
	{
		return this.next;
	}
	//新节点找到合适的位置
	public void addNode(Node newnode)
	{
		if (this.getNext() == null)			//当前节点指向空,则可以把新节点排在这
		{
			this.setNext(newnode);
		}else
		{
			this.getNext().addNode(newnode);
		}
	}
	//类中查找数据
	public boolean containsNode(String data)
	{
		if (this.getData().equals(data))			//当前相等
		{
			return true;
		}
		else if (this.getNext() == null)			//找完了
		{
			return false;
		}
		else					//还要继续找
		{
			return this.getNext().containsNode(data);
		}
	}
	//类中打印数据
	public void printNode()
	{
		System.out.println(this.getData());		//输出当前的数据
		if (this.getNext() != null)				//还有下一个节点
		{
			this.getNext().printNode();
		}
	}
}
class Link			//链表操作类
{
	private Node root;	//定义根节点
	public void add(String data)			//增加数据,需要把数据变为节点
	{
		Node newnode = new Node(data);
		if (this.root == null)				//根节点为空
		{
			this.root = newnode;
		}else 
		{
			this.root.addNode(newnode);
		}
	}
	public void print()						//输出的全部数据
	{
		if (this.root != null)
		{
			this.root.printNode();
		}
	}
	public boolean contains(String data)			//定义查找数据的方法
	{
		if (this.root == null && data == null && "".equals(data))
		{
			return false;							//不用判断
		}
		return this.root.containsNode(data);			//否则调用Node类中的查找
	}
}
public class TestChain
{
	public static void main(String [] args)
	{
		Link link = new Link();
		String root = "火车头";
		String n1 = "车厢1";
		String n2 = "车厢2";
		String n3 = "车厢3";
		link.add(root);
		link.add(n1);
		link.add(n2);
		link.add(n3);
		link.print();
		System.out.println(link.contains("火车头1"));
	}
}
结果:
解释
首先判断根节点是否存在,不存在直接返回false。存在用根节点开始调用查找函数。在该函数中,首先判断当前节点的属性是否相同,相同返回true;否则判断如果next指向空了,则false,否则用next递归调用。

2.3数据删除操作

能查找就能删除,因为删除之前必须保证删除的节点存在。删除节点就是空出节点的过程。在删除的过程中注意是否是根节点,如果是根节点,不同节点的删除方式不同。

案例:

class Node				//建立节点类,节点中保存数据和下一个对象
{
	//封装属性
	private String data;	//建立数据,可以是任何数据类型
	private Node next;		//作为连接的下一个对象
	//构造方法
	public Node(String data)
	{
		this.data = data;
	}
	//属性的获取和设置方法
	public void setData(String data)
	{
		this.data = data;
	}
	public String getData()
	{
		return this.data;
	}
	public void setNext(Node next)
	{
		this.next = next;
	}
	public Node getNext()
	{
		return this.next;
	}
	//新节点找到合适的位置
	public void addNode(Node newnode)
	{
		if (this.getNext() == null)			//当前节点指向空,则可以把新节点排在这
		{
			this.setNext(newnode);
		}else
		{
			this.getNext().addNode(newnode);
		}
	}
	//类中查找数据
	public boolean containsNode(String data)
	{
		if (this.getData().equals(data))			//当前相等
		{
			return true;
		}
		else if (this.getNext() == null)			//找完了
		{
			return false;
		}
		else					//还要继续找
		{
			return this.getNext().containsNode(data);
		}
	}
	//类中删除数据
	public void deleteNode(String data)
	{
		if (this.getNext().getData().equals(data))
		{
			this.setNext(this.getNext().getNext());
		}else if (this.getNext().getNext() !=null)
		{
			this.getNext().deleteNode(data);
		}
	}
	//类中打印数据
	public void printNode()
	{
		System.out.println(this.getData());		//输出当前的数据
		if (this.getNext() != null)				//还有下一个节点
		{
			this.getNext().printNode();
		}
	}
}
class Link			//链表操作类
{
	private Node root;	//定义根节点
	public void add(String data)			//增加数据,需要把数据变为节点
	{
		Node newnode = new Node(data);
		if (this.root == null)				//根节点为空
		{
			this.root = newnode;
		}else 
		{
			this.root.addNode(newnode);
		}
	}
	public void print()						//输出的全部数据
	{
		if (this.root != null)
		{
			this.root.printNode();
		}
	}
	public boolean contains(String data)			//定义查找数据的方法
	{
		if (this.root == null && data == null && "".equals(data))
		{
			return false;							//不用判断
		}
		return this.root.containsNode(data);			//否则调用Node类中的查找
	}
	//删除
	public void delete(String data)
	{
		if (this.contains(data))					//要删除的节点是存在的
		{
			if (this.root.getData().equals(data))		//说明要删除的内容是根节点,则根赋值为后面的节点
			{
				this.root = this.root.getNext();
			} else
			{
				this.root.deleteNode(data);
			}
		}
	}
}
public class TestChain
{
	public static void main(String [] args)
	{
		Link link = new Link();
		String root = "火车头";
		String n1 = "车厢1";
		String n2 = "车厢2";
		String n3 = "车厢3";
		link.add(root);
		link.add(n1);
		link.add(n2);
		link.add(n3);
		link.print();
		System.out.println(link.contains("火车头1"));
		link.delete("车厢3");
		link.delete("车厢1");
		System.out.println("删除之后的结果:");
		link.print();
	}
}
结果:

这里的删除要先用查找进行判断,具体过程不再解释。

核心:this关键字的使用,引用传递。

祝大家健健康康,快快乐乐。

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值