Java语言实现双链表

java语言实现双链表其实很简单,双链表的基本操作有:增、删、改、差、取得指定节点的内容、判空、节点个数、清除、输出。
相对比较难一点的是链表的删除,这里说明一下具体的实现删除可以在外部写一个删除的方法,此处用的方法非常容易理解,不
用像以前那样考虑是否为头结点、是否为空等等,只需要两步操作即可。具体操作在代码中展示:

代码实现如下:
interface ILink {
	void add(Object obj); // 增

	boolean remove(Object obj); // 删

	Object set(int index, Object newData); // 替换

	Object get(int index); // 取得指定节点的内容

	int contains(Object data); // 判断节点内容是否存在

	int size(); // 节点个数

	void clear(); // 清除

	Object[] toArray(); // 将链表转化为数组

	void printLink(); // 输出
}

class LinkImpl implements ILink {
	private Node head; // 设置头结点
	private Node last; // 设置尾节点
	private int size; // 设置节点个数

	private class Node { // 通过内部类设置节点
		private Node pre; // 前指针
		private Node next; // 后指针
		private Object data; // 节点数据

		public Node(Node pre, Node next, Object data) {
			this.pre = pre;
			this.next = next;
			this.data = data;
		}
	}

	@Override
	public void add(Object obj) { // 采用尾插的方式
		Node temp = this.last; // 保存当前链表的尾节点
		Node newNode = new Node(temp, null, obj); // 设置新节点
		this.last = newNode; // 因为是尾插的方式,先让链表的尾节点指向新节点
		if (this.head == null) { // 如果链表为空,直接插入
			this.head = newNode;
		} else {
			temp.next = newNode; // 如果链表不为空,让当前链表的尾节点指向新节点
		}
		this.size++; // 插入节点完成,节点个数++
	}

	@Override
	public boolean remove(Object obj) {
		if (obj == null) { // 若要删除的节点为空节点
			for (Node temp = head; temp != null; temp = temp.next) {
				if (temp.data == null) { // 找到空节点
					unLink(temp); // 删除
					return true;
				}
			}
		} else { // 要删除节点不为空
			for (Node temp = head; temp != null; temp = temp.next) {
				if (obj.equals(temp.data)) { // 找到该节点
					unLink(temp); // 删除该节点
					return true;
				}
			}
		}
		return false;
	}

	@Override
	public Object set(int index, Object newData) {
		if (!isLinkIndex(index)) { // 判断该节点是否存在
			return null;
		}
		Object result = node(index).data; // 保存该节点的data
		node(index).data = newData; // 设置新的data
		return result; // 返回
	}

	@Override
	public Object get(int index) {
		if (!isLinkIndex(index)) { // 判断该节点是否存在
			return null;
		}
		return node(index).data; // 返回该下标的节点
	}

	@Override
	public int contains(Object data) {
		int i = 0;
		if (data == null) { // 若要查找节点为空节点
			for (Node temp = head; temp != null; temp = temp.next) {
				if (temp.data == null) {
					return i;
				}
				i++;
			}
		} else { // 若要查找节点不为空节点
			for (Node temp = head; temp != null; temp = temp.next) {
				if (data.equals(temp.data)) {
					return i;
				}
				i++;
			}
		}
		return -1; // 找不到返回-1
	}

	@Override
	public int size() {
		return this.size;
	}

	@Override
	public void clear() {
		for (Node temp = head; temp != null;) {
			Node flag = temp.next;
			temp.pre = temp = temp.next = null;
			temp = flag;
			this.size--;
		}
	}

	@Override
	public Object[] toArray() {
		Object[] result = new Object[this.size];
		int i = 0;
		for (Node temp = head; temp != null; temp = temp.next) {
			result[i++] = temp.data;
		}
		return result;
	}

	@Override
	public void printLink() {
		Object[] data = this.toArray();
		for (Object temp : data) {
			System.out.println(temp);
		}
	}

	// ==========================
	// 根据下标返回节点
	private Node node(int index) {
		if (index < (this.size >> 1)) { // 小于中间节点下标,从前往后找
			Node temp = head;
			for (int i = 0; i < index; i++) {
				temp = temp.next;
			}
			return temp;
		} else {
			Node temp = this.last;
			for (int i = this.size - 1; i > index; i--) {
				temp = temp.pre;
			}
			return temp;
		}
	}

	// 判断传入结点的下标是否存在
	private boolean isLinkIndex(int index) {
		return index >= 0 && index < this.size;
	}

	// 删除节点
	private void unLink(Node node) {
		Node nodePre = node.pre; // 保存要删除节点的前一个节点
		Node nodeNext = node.next; // 保存要删除节点的下一个节点
		// 先判断前指针(pre指针域)
		if (node.pre == null) { // 如果要删除节点为头结点
			this.head = nodeNext; // 当前头结点指向该节点下一个节点
		} else {
			nodePre.next = nodeNext; // 前一个节点的next域指向该节点的next
			node.pre = null; // 释放该节点的前指针域(pre)
		}
		// 再判断后指针(next指针域)
		if (node.next == null) { // 如果要删除的节点为尾节点
			this.last = nodePre; // 当前的尾节点指向该节点的前一个节点
		} else {
			nodeNext.pre = nodePre; // 下一个节点的pre域指向该节点的pre
			node.next = null; // 释放该节点的后指针域(next)
		}
		node.data = null; // 释放该节点的值域(data)
		this.size--; // 节点个数减1
	}
}

代码检测:

1、插入的检测(采用尾插):

代码:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");
        link.printLink();

    }
}

运行结果:

2、删除操作的检测:(如果删除成功返回true,失败返回false)

代码:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");

        link.remove("节点2"); // 删除节点2
        System.out.println(link.remove("节点6")); // 删除一个不存在的节点-->会返回false

        link.printLink();

    }
}

运行结果:

3、替换(根据指定位置替换)

代码:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");

        link.set(2,"Hello World!!!"); // 把下标为2的节点改为Hello World

        link.printLink();

    }
}

运行结果:

4、 查找(根据下标查找该节点的值)

代码:

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");

        System.out.println(link.get(2)); // 查找下标为2的节点的值
        
    }
}

运行结果:

5、判断链表中该节点是否存在(存在,返回该节点的值,不存在,返回null)

public class Test{
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");

        System.out.println(link.get(2)); // 查找下标为2的节点的值
        System.out.println(link.get(5)); // 查找一个不存在的节点

    }
}

运行结果:

6、输出节点的个数(清除节点后输节点的个数)

代码:

public class Test {
    public static void main(String[] args) {
        ILink link = new LinkImpl();
        link.add("头结点");
        link.add("节点1");
        link.add("节点2");
        link.add("节点3");
        link.add("尾节点");
        link.printLink();
        
        System.out.println("==========================");
        System.out.println("未清除之前节点个数为:" + link.size());
        System.out.println("==========================");
        link.clear();
        System.out.println("清除后节点个数为:" + link.size());

    }
}

运行结果:

猜你喜欢

转载自blog.csdn.net/Zero_975/article/details/83791150