JAVA单链表

java单链表

一、直接对Node进行操作
class Node<E>{
	private E data;
	private Node<E> next;
	public Node (E data){
		this.data = data;
	}
	public E getData(){
		return this.data;
	}
	public void setNext(Node<E> next){
		this.next = next;
	}
	public Node<E> getNext(){
		return this.next;
	}
}
public class javaDemo {
	public static void main(String args[]) {
		Node<String> n1 = new Node<String>("Node 1");
		Node<String> n2 = new Node<String>("Node 2");
		Node<String> n3 = new Node<String>("Node 3");
		Node<String> n4 = new Node<String>("Node 4");
		Node<String> n5 = new Node<String>("Node 5");
		n1.setNext(n2);
		n2.setNext(n3);
		n3.setNext(n4);
		n4.setNext(n5);
		printNode(n1);
	}
	public static void printNode(Node<?> node){
		if(node != null){
			System.out.println(node.getData() + "  ");
			printNode(node.getNext());
		}
	}
}

可以看出让用户直接对Node类进行操作是十分复杂的,而且不利于链表内容的管理。我们想得到的只是“链表”这个类和对链表的操作方法,对于节点的增删查改都可以作为方法封装起来。下面尝试实现。

二、利用内部类实现

首先我们需要定义一个接口ILink,在这个接口中,我们定义有链表需要具备的一些操作方法,同时接口设置泛型,便于管理各种类型的数据。

interface ILink<E>{
	public void add(E e);//向链表中追加数据
	public int size();//获取链表数据个数
	public boolean isEmpty();//判断链表是否为空
	public Object[] toArray();//将元素以数组的形式返回
	public E get(int index);//通过索引获得数据
	public void set(int index,E data);//修改指定索引的数据
	public boolean contains(E data);//查询指定元素是否存在
	public void remove(E data);//删除数据 传递的是数据内容
	public void clean();//清空链表
}

接下来我们实现这个接口。

class LinkImpl<E> implements ILink<E>{
	private class Node<E>{
		//定义一个Node内部类
		private E data;//Node类中属性,用于存放该节点的数据
		private Node<E> next;//Node类中属性,下一个节点
		public Node(E data){
			this.data = data;
		}//Node类构造方法
		public void addNode(Node<E> newNode){
		//添加新的Node节点,注意这只是Node类中的一个方法,并不能把数据添加到链表中
			if(this.next == null){
			//如果this已经指向了链表尾部,那么直接将其添加到this.next;
				this.next = newNode;
			}else{//如果this还没有指向链表尾部,那么要向后寻找,递归调用该方法,直到其指向链表尾部
				this.next.addNode(newNode);
			}
		}
		
		public void toArrayNode(){
		//递归调用该方法,并且将returnData数组逐一填充
			LinkImpl.this.returnData[LinkImpl.this.foot ++] = this.data;
			if(this.next != null){
				this.next.toArrayNode();
			}
		}
		public E getNode(int index){
		//判断index是否与foot相等,如果不等,就判断下一个节点
			if(LinkImpl.this.foot ++ == index){
				return this.data;
			}else{
				return this.next.getNode(index);
			}
		}
		public void setNode(int index,E data){
		//核心方法同getNode(),核心是找到index对应的节点
			if(LinkImpl.this.foot ++ == index){
				this.data = data;
			}else{
				this.next.setNode(index,data);
			}
		}
		public boolean containsNode(E data){
		//遍历链表,从第一个开始,如果相同返回true,否则判断下一个节点,直到最后一个;
			if(this.data.equals(data)){
				return true;
			}else{
				if(this.next == null){
					return false;
				}else{
					return this.next.containsNode(data);
				}
			}
		}
		public void removeNode(Node<E> previous,E data){
		//
			if(this.data.equals(data)){
				previous.next = this.next;
			}else{
				if(this.next != null){
					this.next.removeNode(this,data);
				}
			}
		}
	}
	
	//------------以下为Link类中定义的成员------------//
	private Node<E> root;//保存根元素
	private int count;//保存链表元素个数
	private int foot;//描述的是操作数组的角标,在涉及到index的方法中用到
	private Object [] returnData;//返回的数据保存在这个数组中
	//------------以下为Link类中定义的方法------------//
	@Override
	public void add(E e){
		if(e == null){//如果保存的数据为null,则直接返回
			return ;
		}
		//数据本身是不具有关联特性的,只有Node类有,那么要想实现数据的关联处理就必须将数据包装在Node中
		Node<E> newNode = new Node<E>(e);//创建一个新的节点,并将数据包装在节点中
		if(this.root == null){//如果这个链表是空链表,则新元素作根
			this.root = newNode;
		}else{//否则调用addNode()方法,将其添加到链表尾部
			  this.root.addNode(newNode);
		}
		this.count++;//
	}

	public int size(){//链表长度
		return this.count;
	}

	public boolean isEmpty(){//判断链表长度是否为空
		return this.count == 0;
		//return this.root == null;
	}

	public Object[] toArray(){//数据返回
		if(this.isEmpty()){
			return null;
		}
		this.foot = 0;
		this.returnData = new Object [this.count];
		//利用Node类进行递归数据获取
		this.root.toArrayNode();
		return this.returnData;
	}
	public E get(int index){//和数组类似,但是数组时间复杂度为1,链表时间复杂度为n
		if(index > this.count){
			return null;
		}//索引数据的获取应该由Node类完成
		this.foot = 0;
		return this.root.getNode(index);
	}
	public void set(int index, E data){
		if(index > this.count){
			return ;
		}
		this.foot = 0;
		this.root.setNode(index,data);
	}
	public boolean contains(E data){
		if(data == null){
			return false;
		}
		return this.root.containsNode(data);
	}
	public void remove(E data){
		if(this.contains(data)){//要删除的是根节点,可以直接让root指向原来root的next
			if(this.root.data.equals(data)){
				this.root = this.root.next;
			}else{//要删除的元素不是根节点,要让这个目标节点前一个节点的next指向目标节点的next
				this.root.next.removeNode(this.root,data);
			}
			this.count--;
		}
	}
	public void clean(){
			this.root = null;
			this.count = 0;
	}
}

下面是一个功能测试的Demo,并不是很完善。

public class javaDemo {
	public static void main(String args[]) {
		ILink<String> all = new LinkImpl<String>();
		all.add("hello");
		all.add("tomorrow");
		all.clean();
		System.out.println(all.isEmpty());
		System.out.println(all.size());
	}	
}
总结

java中可以通过内部类可以访问外部类私有属性这一特点将节点Node类封装在LinkList类中,从而方便地实现单链表,用户只需要对链表进行操作,而对节点的操作完全封装在了类中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值