写给自己的JAVA工程师之路-链表

1.1 认识链表

链表 = 可变长的对象数组,属于动态对象数组的范畴。

传统对象数组:

作用:对象数组可以保存一组对象方便开发。
缺点:对象数组的长度固定,而且数据的修改,删除,增加处理麻烦。

正因为如此,如果想要让其编写出便于维护的代码,那么就需要实现一个动态对象数组,于是可以使用链表完成。

1.2 实现链表

问题:保存数据为了方便使用Object;
   
           数据本身不包含有先后的逻辑关系,所以将数据封装在一个Node类,负责关系的维护。

class Node{//表示定义的节点
	private Object data;//表示保存的数据
	private Node next;//保存下一个节点
	public Node(Object data){//有数据才可以保存节点
		this.data=data;
	}
	public void setNext(Node next){//设置节点
		this.next=next;
	}
	public Node getNext(){//取得节点
		return this.next;
	}
}
链表在整个实现过程最关键的就是Node类,Node类要保存数据与下一个节点。

虽然以上的代码已经实现了链的形式,但是实际上Node类对用户没有。所以还需要一个类,这个类可以负责所有Node的关系匹配,而用户只需通过这个类保存数据,取得数据即可。

于是代码变成:

class Node{//表示定义的节点
	private Object data;//表示保存的数据
	private Node next;//保存下一个节点
	public Node(Object data){//有数据才可以保存节点
		this.data=data;
	}
	public void setNext(Node next){//设置节点
		this.next=next;
	}
	public Node getNext(){//取得节点
		return this.next;
	}
	public Object getData(){//取得数据
		return this.data;
	}
	//第一次调用:this=Link.root
	//第二次调用:this=Link.root.next
	//第三次调用:this=Link.root.next.next
	public void addNode(Node newNode){
		if(this.next==null){//当前节点后没有节点
			this.next=newNode;
		}else{//当前节点后有节点
			this.next.addNode(newNode);
		}
	}
	public void printNode(){
		System.out.println(this.data);
		if(this.next!=null){
			this.next.printNode();
		}
	}
}

class Link{//表示一个链表操作类,利用此类来隐藏Node的节点匹配
	private Node root;//根元素
	public void add(Object obj){//向链表里追加数据
		Node newNode = new Node(obj);//将数据包装为Node对象,这样才可以进行先后关系排列
		//没有根节点时
		if(this.root==null){
			this.root=newNode;//第一个节点作为根节点
		}else{//根节点存在,交由Node处理
			this.root.addNode(newNode);
		}
	}
	public void print(){//输出全部数据
		this.root.printNode();
	}
}

链表在整个实现过程最关键的就是Node类,Node类要保存数据与下一个节点。

2.1 开发可用链表

以上的代码只能够说是基本的链表形式,可是如何才能实现一个好的链表呢?

1.让Node类只为Link类服务,但是又不让其他类访问。
2.如果要开发程序,那么一定要创建出自己的操作标准,那么一旦说到标准,就应该使用到接口完成。

于是代码结构变成:
interface Link{
	
}
class LinkImpl implements Link{
	private class Node{//使用私有内部类,防止外部使用此类
		private Object data;//表示保存的数据
		private Node next;//保存下一个节点
		public Node(Object data){//有数据才可以保存节点
			this.data=data;
		}
	}
	//*******************************************
	private Node root;//根节点
}
在随后完善的代码过程之中,除了功能的实现之外,实际上也属于接口功能的完善。

2.2 完整链表实现

interface Link{
	public void add(Object data);//数据增加
	public int size();//获得链表大小
	public boolean isEmpty();//判断是否为空集合
	public boolean contains(Object data);//判断是否存在指定元素
	public Object get(int index);//根据索引取得数据
	public void set(int index,Object obj);//修改数据
	public void remove(Object data);//数据删除
	public void clear();//清空链表
	public Object[] toArray();//对象数组转换
}
class LinkImpl implements Link{
	private class Node{//使用私有内部类,防止外部使用此类
		private Object data;//表示保存的数据
		private Node next;//保存下一个节点
		public Node(Object data){//有数据才可以保存节点
			this.data=data;
		}
		//第一次调用:this=LinkImpl.root
		//第二次调用:this=LinkImpl.root.next
		//第三次调用:this=LinkImpl.root.next.next
		public void addNode(Node newNode){
			if(this.next==null){//当前节点后没有节点
				this.next=newNode;
			}else{//当前节点后有节点
				this.next.addNode(newNode);
			}
		}
		public boolean containsNode(Object data){
			if(this.data.equals(data)){//该节点数据束符合于查找数据
				return true;
			}else {//继续向下查找
				if(this.next!=null){//当前节点还有下一个节点
					return this.next.containsNode(data);
				}else {
					return false;
				}
			}
		}
		public Object getNode(int index){//传递索引序号
			if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引
				return this.data;//返回节点对象
			}else {
				return this.next.getNode(index);
			}
		}
		public void setNode(int index,Object data){
			if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引
				this.data=data;//重新保存数据
			}else {
				this.next.setNode(index, data);
			}
		}
		public void removeNode(Node pre,Object data){
			if(this.data.equals(data)){//为当前要删除的数据
				pre.next=this.next;
			}else {
				pre.next.removeNode(this, data);
			}
		}
		public void toArrayNode(){
			LinkImpl.this.retData[LinkImpl.this.foot++]=this.data;
			if(this.next!=null){
				this.next.toArrayNode();
			}
		}
	}
	//*******************************************
	private Node root;//根节点
	private int count=0;//纪律链表大小
	private int foot=0;//操作的索引脚标
	private Object retData[]=null;
	public void add(Object data){
		if(data==null){//没有增加的数据
			return ;//结束调用
		}
		Node newNode = new Node(data);//将数据包装为Node对象,这样才可以进行先后关系排列
		//没有根节点时
		if(this.root==null){
			this.root=newNode;//第一个节点作为根节点
		}else{//根节点存在,交由Node处理
			this.root.addNode(newNode);
		}
		this.count++;//添加成功 ,链表长度+1
	}
	public int size(){//获得链表大小
		return this.count;
	}
	public boolean isEmpty(){
		return this.root==null;
	}
	public boolean contains(Object data) {
		if(this.root==null){
			return false;
		}
		return this.root.containsNode(data); 
	}
	public Object get(int index) {
		if(index>=this.count){//索引不存在
			return null;
		}
		this.foot=0;//查询之前进行初始化
		return this.root.getNode(index);
	}
	public void set(int index, Object obj) {
		if(index>=this.count){//索引不存在
			return ;
		}
		this.foot=0;//查询之前进行初始化
		this.root.setNode(index, obj);
	}
	public void remove(Object data) {
		if(this.contains(data)){//数据如果存在即删除
			if(this.root.data.equals(data)){//跟元素为要删除的元素
				this.root=this.root.next;
			}else {//不是根元素
				this.root.next.removeNode(this.root, data);
			}
		}
		count--;
	}
	public void clear() {
		this.root=null;
		this.count=0;
		System.gc();//内存清空
	}
	public Object[] toArray() {
		if(this.root==null){
			return null;
		}
		this.retData=new Object[this.count];
		this.foot=0;
		this.root.toArrayNode();
		return this.retData;
	}
}
以上的设计都没有考虑过性能问题,只是简单的单向链表,重点是方法的理解与实现



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值