链表开发案例

package com.start;

public class LinkDemo {

	public static void main(String[] args) {
		Link all = new Link(); //创建链表对象
		all.add(new Book("Java开发", 89.56));
		all.add(new Book("Oracle数据库开发", 99));
		all.add(new Book("Androld开发", 56.2));
		
		System.out.println("保存的节点有:"+all.size());
		System.out.println(all.contains(new Book("Java实战经典", 78.8)));
		
		all.contains(new Book("Android开发实战经典", 78.8));
//		all.remove(new Book("Java开发",89.56));
		all.remove(new Book("Oracle数据库开发", 99));
		all.remove(new Book("Androld开发", 56.2));
		Book[] books = all.toArray();
//		for(int x = 0 ;x<books.length; x++) {
//			System.out.println(books[x]);
//		}
	}
}
/**
 * 定义一个类保存图书信息
 * 		保存图书测名称、图书的价格
 * 		compare()方法判断对是否和Book对象相同
 * @author Administrator
 *
 */
class Book{
	private String title ;
	private double price;
	public Book(String title, double price) {
		super();
		this.title = title;
		this.price = price;
	}
	/**
	 * 进行对本类对象比较,首先判断是否为null,在判断地址是否相同
	 * 如果都相同再进行对象内容判断,由于compare()方法就收的是本类引用,所以直接访问私有属性
	 * @param book
	 * @return
	 */
	public boolean compare(Book book) {
		if(book == null) {
			return false ;
		}
		if(this == book) { // 直接判断内存地址
			return true ;
		}
		if(this.title.equals(book.title) && this.price==book.price) {
			return true;
		}else {
			return false;
		}
	}
	//覆写toString()方法
	public String getInfo() {
		return "图书名称是:"+this.title+"图书价格:"+this.price;
	}
}
/**
 * 创建链表是实现类
 * @author Administrator
 *
 */
class Link{
	/***
	 * 定义Node节点操作类
	 * @author Administrator
	 *
	 */
	/******************************内部类操作节点关系****************************************/
	private class Node{
		private Book data ;//保存数据
		private Node next ;//保存下一个节点
		public Node() {
			super();
		}
		public Node(Book data) {
			this.data = data ;// 保存节点数据
		}
		/***
		 * 保存新的节点,所有的节都保存在最后一个节点之后
		 * 		如果当前节点不是下一个将节点,那么继续寻找下一个节点,下一个节点还不是最后一个节点,在递归继续寻找。找到最后一个节点为止,找到最后一个节点之后把当前添加的节点保存在下一个(next)节点对象中
		 * @param newNode
		 */
		public void addNode(Node newNode) {
			if(this.next == null) { //判断是当前节点是否为最后一个节点,如果next为null,则为最后一个节点
				this.next = newNode; //因为next表示下一个节点,如果next为null的,说明这里没有下一个节点了,就发newNode新的节点保存在next下一个节点的位置
			}else {
				this.next.addNode(newNode);//证明还有下一个节点,在继续判断。这里当前对象点next下一个节点时,已经是判断下一个节点的数据了
			}
		}
		/**
		 * 数据检索操作(指定数据查询是否存在)
		 * 	
		 * @param data 需要查询的数据
		 * @return
		 */
		public boolean containsNode(Book data) {
			if(this.data.compare(data)) { //判断当前对象data和传过来的data对象是否相同        compare()方法专门为Book对象比较而设计
				return true;
			}else {
				if(this.next.data.compare(data)) { //如果不存用户传输过来的data不在当前对象中,那么在去下一个对象中寻找
					return true ;
				}else {
					return false;
				}
			}
		}
		/**
		 * 根据索引取出数据
		 * @return
		 */
		public Book getNode(int index ){
			if(Link.this.foot == index) {
				return this.data;//返回数据
			}else {
				return this.next.getNode(index); //递归,下一个节点在判断
			}
		}
		/****
		 * 指定下标修改数据
		 * @param idnex
		 * @param data
		 */
		public void setNode(int index,Book data) {
			if(Link.this.foot == index) { //根据指定的下标查询到对应节点
				this.data = data ;//参数传过来的数据f覆盖原来节点上的数据
			}else {
				this.next.setNode(index, data);//如果没有,下一个节点继续
			}
		}
		/***
		 * 节点删除操作,匹配每一个节点的数据,如果当节点数据符合则删除
		 * @param previous
		 * @param data
		 */
		public void removeNode(Node previous,Book data) {
			if(data.compare(this.data)) { //参数传过来的节点与当前节点比较,
				previous.next = this.next;//空出当前节点。如果data与当期节点相同了,那么把当前节点赋值给previous对象
			}else {
				this.next.removeNode(previous, data);//如果两个对象不相同,下一个节点继续
			}
		}
		/**
		 * 把当前节点内容保存到数组中
		 */
		public void toArrayNode() {
			Link.this.retArray[Link.this.foot] = this.data; //Link.this.foot为下标。把当前对象保存到数组中
		}
	}
	/******************************内部类操作结束****************************************/
	private Node root ;//保存节点定义
	private int cunt = 0 ;//保存节点个数
	private  int foot ;//保存节点下标
	private Book[] retArray;//返回数组
	
	/***
	 * 向链表中添加数据,在添加数据时必须封装到Node类中,这样才能匹配节点数据
	 * @param data
	 */
	public void add(Book data) {
		if(data == null) {
			return ;
		}
		Node newNode = new Node(data); //需要保存的数据
		if(this.root==null) { //判断当前节点是否为空节点
			this.root = newNode; //把节点数据保存在根节点中
		}else { //如果不是空节点,就交给Node去处理节点顺序
			this.root.addNode(newNode);
		}
		this.cunt++;//节点的个数增加 +1
	}
	/**
	 * 取得节点中的个数
	 * @return
	 */
	public int size() {
		return this.cunt;
	}
	/**
	 * 判断是否为空链表
	 * @return
	 */
	public boolean isEmpty() {
		return this.cunt == 0 ;
	}
	/**
	 * 数据查询操作,判断指定数据是否存在,如果链表中没有数据则返回false
	 * @param data
	 * @return
	 */
	public boolean contains(Book data) {
		if(data == null || this.root == null) { //root保存的是根节点,如果根节点为null,那么说名该链表中没有数据的。如果查询的参数data为null,链表中冶不会存在的
			return false;
		}
		return this.root.containsNode(data);//Node内部类中去查询
	}
	/***
	 * 根据下标查询数据
	 * @param index
	 * @return
	 */
	public Book get(int index) {
		if(index >this.cunt) { //判断查询的下标是否在链表保存节点个数的范围内
			return null ;
		}
		this.foot =0;//表示存第一个开始查询
		return root.getNode(index);//内部类处理
	}
	/***
	 * 根据下标修改数据
	 * @param index 修改数据的下标
	 * @param data  需要修改的内容
	 */
	public void set(int index,Book data) {
		if(index > this.cunt) { //判断index是超过链表范围内
			return;//结束方法调用
		}
		this.foot = 0 ;//存第一个开始查询
		this.root.setNode(index, data);//交给内部类处理
	}
	/***
	 * 链表数据的删除操作,在删除前首先适应contains()判断链表中是否存在指定的数据
	 * 如果要是删除数据,首先判断根节点的数据是否需要删除
	 * 如果是,则将根节点的下一个节点作为新根节点
	 * 如果删除的数据不是根节点数据,则将删除操作交给Node内部类removeNode()方法去处理
	 * @param data
	 */
	public void remove(Book data) {
		if(this.contains(data)) { //判断数据是否存在
			//判断删除的数据是否为根节点数据,root是Node类的对象,removeNode()方法完成
			if(data.equals(this.root.data)) { //这里的root保存的是节点中的定义,this.root.data为根节点   【删除的数据为根节点数据】
				this.root = this.root.next;//空出当前节点 ,让下一个节点作为当前节点
			}else {//删除的数据不是根节点数据
				//此时根节点元素已经判断过了,从第二个元素开始判断,从第二个元素的上一个元素为根节点(因为根节点没有删除)
				this.root.removeNode(this.root, data); //交给内部类处理
			}
			this.cunt -- ;//节点个数减 -1
		}
	}
	/***
	 * 将链表中的数据转为数组输出
	 * @return  如果链表没有数据返回 null
	 */
	public Book[] toArray() {
		if(this.root == null) { //判断链表是否为null
			return null;
		}
		this.foot = 0 ;//索引从0开始
		this.retArray= new Book[this.cunt]; //根据保存的数据开辟内存
		this.root.toArrayNode(); //交给Node类处理赋值操作
		return this.retArray;
	}
	/**
	 * 清空链表
	 */
	public void clear() {
		this.root = null ;
		this.cunt = 0;
	}
}