JAVA数据结构之链表

3 篇文章 0 订阅
1 篇文章 0 订阅

链表:单链表,双链表,循环链表

 

单链表:每个节点有一个内容和一个地址,这个地址指向下一个节点。

第一个加入链表的节点为头结点,它的地址指向第二个节点,第二个节点地址指向第三个节点。。。最后一个节点的地址指向null。

如图所示:



 

 

由这样的关系,我们容易得知只要知道first,我们就可以用first.next.next.....取到每一个节点元素。

对于单链表,我们要实现他的创建,添加,插入,删除,查询(遍历)等方法。

下面的程序只实现了基本的创建与遍历。其余均在双链表会实现。方法类似。

Node.java

package 单链表LinkedList的实现;

/**
 * 节点 包括 内容,地址
 * 
 * @author Huangbin
 *
 */
public class Node<E> {

	E elem;// 节点中的内容

	Node<E> next;// 对下一个节点的引用(下个节点也是Node类型的)

	public Node(E elem) {
		this.elem = elem;
	}

	public String toString() {
		return (String) elem;
	}
}

LinkList.java

package 单链表LinkedList的实现;

public class LinkList {

	public static void main(String[] args) {
		LinkList list = new LinkList();
		Node<String> node = list.creat();
		list.print2(node);
	}

	public Node<String> creat() {
		Node<String> node = new Node<String>("1");
		Node<String> node2 = new Node<String>("2");
		Node<String> node3 = new Node<String>("3");
		Node<String> node4 = new Node<String>("4");

		node.next = node2;
		node2.next = node3;
		node3.next = node4;

		return node;
	}

	/**
	 * 用循环遍历
	 * 
	 * @param head
	 */
	public void print(Node head) {
		Node node = head;
		while (node != null) {
			System.out.println(node);
			node = node.next;
		}
	}

	/**
	 * 用递归遍历
	 * 
	 * @param head
	 */
	public void print2(Node head) {
		if (head != null) {
			System.out.println(head);
			print2(head.next);// 递归 调用本身
		}
	}
}


运行结果:
1
2
3
4

 

双链表:

每个节点包含三部分,指向前一个元素的地址,内容,指向后一个元素的地址。每两个节点都会互相指向对方,一般习惯把第一个加进链表的节点成为头节点。最后一个为尾节点

关系如图所示



 

双链表的插入说明:(删除类似)


 

 

 

在双链表中,实现了一些常用的方法。具体见代码:

package 双链表LinkedList的实现;

import java.util.NoSuchElementException;

/**
 * 双链表
 * @author Huangbin 
 * d2014年7月17日
 * @param <E>
 */
public class LinkList<E> {

	Node<E> first;
	Node<E> last;
	private int length = 0;
	static LinkList list;

	public static void main(String[] args) {
		long t1 = System.currentTimeMillis();
		list = new LinkList<String>();
		list.test();
		long t2 = System.currentTimeMillis();
		System.out.println(t2 - t1);
	}

	public void test() {

		Node<Integer> node = new Node<Integer>(1);
		Node<Character> node2 = new Node<Character>('a');
		Node<Double> node3 = new Node<Double>(3.01);
		Node<Float> node4 = new Node<Float>(0.11f);// 8有效数字
		Node<Byte> node5 = new Node<Byte>((byte) 5);
		Node<String> node6 = new Node<String>("字符串6");
		Node<Boolean> node7 = new Node<Boolean>(true);
		Node<Boolean> node8 = new Node<Boolean>(false);
		Node<Boolean> node9 = new Node<Boolean>(false);
		Object arr[];
		list.add(node);
		list.add(node2);
		list.add(node3);
		list.add(node4, 3);
		list.add(node5);
		list.add(node6);
		list.add(node7);
		list.removeLast();
		list.printHead(first);
		arr = list.toArray();
		for (int i = 0; i < length; i++) {
			System.out.println(arr[i]);
		}
		System.out.println("Size: " + length);
	}

	public void printHead(Node<E> first) {
		if (first != null) {// 存在元素
			System.out.print(first.front);
			System.out.print("\t" + first);
			System.out.println("\t" + first.next);
			printHead(first.next);// 递归 调用本身
		}
	}

	/**
	 * 添加元素
	 * 
	 * @param node
	 */
	public void add(Node<E> node) {
		if (first != null) {// 已经存在元素了
			node.front = last;
			last.next = node;
		} else {
			// 添加第一个节点 头尾均指向第一个节点
			first = node;
		}
		last = node;// 重新指向最后一个节点
		length++;
	}

	/**
	 * 在指定位置插入新的元素
	 * 
	 * @param node
	 * @param num
	 */
	public void add(Node<E> node, int num) {
		if (num > length || num < 0) {
			throw new IndexOutOfBoundsException("Index: " + num + ", Size: "
					+ length);
		}
		if (num == 0) {
			if (first != null) {
				node.next = first;
				first.front = node;
				first = node;
			} else {
				add(node);// 不存在直接加进去。
			}
		} else if (num == length) {
			add(node);
		} else {

			Node<E> temp = first;
			for (int i = 1; i < num; i++) {
				temp = temp.next;
			}
			// 此时,temp指向了num位置
			node.front = temp;
			node.next = temp.next;
			temp.next.front = node;
			temp.next = node;
		}
	}

	/**
	 * 移除指定元素
	 * 
	 * @param node
	 */
	public Node<E> remove(Node<E> node) {
		// 先判断是否在链表中
		if (this.contains(node)) {
			// 遍历链表找到node元素的front与next改变他们的指向

			if (node.front != null && node.next != null) {// node是中间位置的元素

				node.next.front = node.front;
				node.front.next = node.next;// node前一个元素指向node的下一个元素

			} else if (node.next != null) {// 被移除的是第一个元素,且存在下一个元素
				first = node.next;
				first.front = null;
			} else if (node.front != null) {// 被移除的是最后一个元素,且存在下一个元素
				last = node.front;
				last.next = null;
			} else {// 移除最后一个元素了,node的前后都是空
				last = first = null;// 这个时候全部被移除了
			}
			// 清空node,释放资源
			// node.next = null;
			// node.front = null;
			// node.elem = null;
			length--;
			return node;
		} else {
			try {
				throw new Exception("不存在 \"" + node + "\" 元素!");
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		}
	}

	/**
	 * 移除指定下标的元素
	 * 
	 * @param num
	 */
	public Node<E> remove(int num) {
		if (num >= length || num < 0) {
			throw new IndexOutOfBoundsException("index:" + num + ",size:"
					+ length);
		}
		Node<E> node = first;
		for (int i = 0; i < num; i++) {
			node = node.next;
		}
		remove(node);
		return node;
	}

	/**
	 * 移除函相同内容的第一个指定元素
	 * 
	 * @return
	 */
	public Node<E> remove(Object o) {
		// 先判断是否在链表中
		if (this.contains(o)) {
			return remove((get(indexOf(o))));
		}
		return null;
	}

	/**
	 * 移除第一个元素
	 * 
	 * @return
	 */
	public Node<E> removeFirst() {
		if (first == null)
			throw new NoSuchElementException();
		return remove(first);
	}

	/**
	 * 移除最后一个元素
	 * 
	 * @return
	 */
	public Node<E> removeLast() {
		if (last == null)
			throw new NoSuchElementException();
		return remove(last);
	}

	/**
	 * 修改指定元素的内容
	 * 
	 * @param str
	 * @param num
	 */
	public void set(E o, int num) {
		get(num).elem = o;
	}

	/**
	 * 获得num下标位置的元素
	 * 
	 * @param num
	 * @return
	 */
	public Node<E> get(int num) {
		if (num >= length || num < 0) {
			throw new IndexOutOfBoundsException("Index: " + num + ", Size: "
					+ length);
		}
		Node<E> node = first;
		for (int i = 0; i < num; i++) {
			node = node.next;
		}

		return node;
	}

	/**
	 * 获得第一个元素
	 * 
	 * @return
	 */
	public Node<E> getFirst() {
		return first;
	}

	/**
	 * 获得最后一个元素
	 * 
	 * @return
	 */
	public Node<E> getLast() {
		return last;
	}

	/**
	 * 获得链表的长度
	 * 
	 * @return
	 */
	public int getSize() {
		return length;
	}

	/**
	 * 添加元素到链表头
	 * 
	 * @param node
	 */
	public void addFirst(Node<E> node) {
		add(node, 0);
	}

	/**
	 * 添加元素到链表尾
	 * 
	 * @param node
	 */
	public void addLast(Node<E> node) {
		add(node);
	}

	/**
	 * 查找元素内容o在哪个位置,不存在返回-1
	 * 
	 * @param o
	 * @return
	 */
	public int indexOf(Object o) {
		int index = 0;
		if (o == null) {
			for (Node<E> x = first; x != null; x = x.next) {
				if (x.elem == null || x == null) {
					return index;
				}
				index++;
			}
		} else {
			for (Node<E> x = first; x != null; x = x.next) {
				if (o.equals(x.elem) || o.equals(x)) {
					return index;
				}

				index++;
			}
		}
		return -1;
	}

	/**
	 * 是否有包含内容o的元素
	 * 
	 * @param o
	 * @return
	 */
	public boolean contains(Object o) {
		return indexOf(o) != -1;
	}

	/**
	 * 队列式取出首元素,先进先出
	 * 
	 * @return
	 */
	public Node<E> queuePop() {
		return removeFirst();
	}

	/**
	 * 栈式取出首元素,后进先出
	 * 
	 * @return
	 */
	public Node<E> statckPop() {
		return removeLast();
	}

	/**
	 * 放元素进去
	 * 
	 * @param node
	 */
	public void push(Node<E> node) {
		add(node);
	}

	/**
	 * 复制该链表
	 */
	public LinkList<E> clone() {
		LinkList<E> clone = new LinkList<E>();
		clone.first = clone.last = null;
		clone.length = 0;
		for (Node<E> node = first; node != null; node = node.next) {
			clone.add(node);

		}
		return clone;
	}

	/**
	 * 把链表转为数组
	 * 
	 * @return
	 */
	public Object[] toArray() {
		Object[] o = new Object[length];
		int i = 0;
		for (Node<E> x = first; x != null; x = x.next, i++) {
			o[i] = x.elem;
		}
		return o;
	}

	private class Node<E> {

		E elem;// 节点中的内容

		Node<E> front;// 对上一个节点的引用(上个节点也是Node类型的)
		Node<E> next;// 对下一个节点的引用(下个节点也是Node类型的)

		public Node(E elem) {
			this.elem = elem;
		}

		public String toString() {
			return (String) "" + elem;//便于打印
		}
	}

}
运行结果:
null	1	a
1	a	3.01
a	3.01	0.11
3.01	0.11	5
0.11	5	字符串6
5	字符串6	null
1
a
3.01
0.11
5
字符串6
Size: 6
3

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值