`
mountain_king
  • 浏览: 16960 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

链表-java实现双向链表

阅读更多

    前面已经总结了单向链表,有兴趣的兄弟可以进我博客看一下。http://mountain-king.iteye.com/blog/715651。。大家对比就可以看出,实现同样的功能单向链表要比双向链表痛苦的多。所以呀不断地总结前辈留下的东西,是社会进步的基础呀。可以直接看LinkedList的源码,其就是个双向链表。

 

一、双向链表的结构。

     (1)、首先节点的结构,其中包含本节点内容,同时需要知道前面是谁后面是谁。 

private static class Entry<E> {
		//元素
		E e;
		//后一个节点
		Entry<E> nextEntry;
		//前一个节点
		Entry<E> previousEntry;

		public Entry(E e, Entry<E> previousEntry, Entry<E> nextEntry) {
			this.e = e;
			this.nextEntry = nextEntry;
			this.previousEntry = previousEntry;
		}
	}

 其中e则指向本节点的元素,而nextEntry则指向下一个节点,previousEntry则指向前一个节点。

 

     (2)、需要定义一个节点,其同时知道表头,同时知道表尾,这里就暂时定义为head。

private transient Entry<E> head = new Entry<E>(null, null, null);

public DoubleChain() {
		head.nextEntry = head.previousEntry = head;
	}

 可以看出,在初始化方法中,直接将表头和表尾直接都指向head。这样在head的基础上不管怎么增加元素都逃脱不了与head关系。牢记head.nextEntry表头,head.previousEntry表尾。

 

     (3)、同样记录节点的个数只是为了提高效率,不是必要。

private int size;

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



  好了有这三样,就足够了。就看我们如何用他们了。

 

二、内部实现。

    (1)、方法addBefore。由于一开始就初始化了head,有了head作为基准,玩转整个链表也就靠这个方法了。

private void addBefore(E e, Entry<E> entry) {
		//新节点的初始化,指定新节点的前一个节点和后一个节点
		Entry<E> newEntry = new Entry<E>(e, entry.previousEntry, entry);
		//告知新节点的前一个节点其后面是新节点
		newEntry.previousEntry.nextEntry = newEntry;
		//告知新节点的后一个节点其前节点是新节点
		newEntry.nextEntry.previousEntry = newEntry;
		size++;
	}

 可以看出,通过指定的元素创建一个新的节点。然后将其前前后后的关系都打通就好了。

 

    (2)、表头插入。再简单不过了,直接在head.nextEntry前增加就好了,直接调用addBefore。效率高

public void addHead(E e) {
		this.addBefore(e, head.nextEntry);
	}

 

    (3)、尾插入。同样简单,直接在head.previous前增加就好了,同样调用addBefore。效率高

public void add(E e) {
		this.addBefore(e, head);
	}

 

 

   (4)、指定节点插入(插队)。同样需要插队,但是由于其节点的双向性,则不需要进行特殊处理,直接循环找出指定的节点元素就好了。效率低

public void addSpecifyIndex(E e, int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				this.addBefore(e, p);
				return;
			}
			count++;
		}
	}

   

    (5)、指定节点获取元素。同样循环找出。效率低

public E get(int index) {
		int count = 0;
		E result = null;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				result = p.e;
			}
			count++;
		}
		return result;
	}

 

    (6)、指定节点删除。同理,找到要删除的节点,让指定节点的前后直接相通就OK了。效率低

public void remove(int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				p.previousEntry.nextEntry= p.nextEntry;
				p.nextEntry.previousEntry=p.previousEntry;
				size--;
				return;
			}
			count++;
		}
	}

 

    (7)、循环。为了好进行遍历演示,下面的就是循环遍历所用的了,大家随意看一下就好了。

private Entry<E> current;

public boolean hasNext() {
		return current != head;
	}

	public E next() {
		E result = current.e;
		current = current.nextEntry;
		return result;
	}

	public void setCursor(int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				current = p;
			}
			count++;
		}

 

三、测试。。一个main方法,测试一下。

public static void main(String[] args) {
		DoubleChain<String> doubleChain = new DoubleChain<String>();
		for (int i = 0; i < 4; i++) {
			doubleChain.add(i + "");
		}
		// 头插入
//		 doubleChain.addHead("head");
//		// 尾插入
//		 doubleChain.add("tail");
//		// 指定节点插入
//		 doubleChain.addSpecifyIndex("Specify", 1);
//		// 指定节点删除
//		 doubleChain.remove(3);
//		// 设置循环的初始节点
//		doubleChain.setCursor(0);
		int count = 0;
		System.out.println("######SIZE" + doubleChain.size() + "#######");
		while (doubleChain.hasNext()) {
			System.out.println("index:" + count + ",entry:"
					+ doubleChain.next());
			count++;
		}

		System.out.println(doubleChain.get(doubleChain.size() - 2));

	}
 

四、总结。。

   可以看出,从结构上讲,双向链表和单项链表最大的区别在于每个节点都是双向的。从效率上讲,提高了尾插入的效率,但是对于插队同样效率不高。如果需要反复进行插队操作的同学注意了,LinkedList的效率会很低的哦。

 

五、全部代码。。

package paladin.chain;


public class DoubleChain<E> implements Chain<E> {

	private transient Entry<E> head = new Entry<E>(null, null, null);

	private Entry<E> current;

	private int size;

	public DoubleChain() {
		head.nextEntry = head.previousEntry = head;
	}

	
	private void addBefore(E e, Entry<E> entry) {
		//新节点的初始化,指定新节点的前一个节点和后一个节点
		Entry<E> newEntry = new Entry<E>(e, entry.previousEntry, entry);
		//告知新节点的前一个节点其后面是新节点
		newEntry.previousEntry.nextEntry = newEntry;
		//告知新节点的后一个节点其前节点是新节点
		newEntry.nextEntry.previousEntry = newEntry;
		size++;
	}

	public void add(E e) {
		this.addBefore(e, head);
	}

	public void addHead(E e) {
		this.addBefore(e, head.nextEntry);
	}

	public void addSpecifyIndex(E e, int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				this.addBefore(e, p);
				return;
			}
			count++;
		}
	}

	public void remove(int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				p.previousEntry.nextEntry= p.nextEntry;
				p.nextEntry.previousEntry=p.previousEntry;
				size--;
				return;
			}
			count++;
		}
	}

	public E get(int index) {
		int count = 0;
		E result = null;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				result = p.e;
			}
			count++;
		}
		return result;
	}

	public boolean hasNext() {
		return current != head;
	}

	public E next() {
		E result = current.e;
		current = current.nextEntry;
		return result;
	}

	public void setCursor(int index) {
		int count = 0;
		for (Entry<E> p = head.nextEntry; p != head; p = p.nextEntry) {
			if (count == index) {
				current = p;
			}
			count++;
		}

	}

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

	private static class Entry<E> {
		//元素
		E e;
		//后一个节点
		Entry<E> nextEntry;
		//前一个节点
		Entry<E> previousEntry;

		public Entry(E e, Entry<E> previousEntry, Entry<E> nextEntry) {
			this.e = e;
			this.nextEntry = nextEntry;
			this.previousEntry = previousEntry;
		}
	}

	public static void main(String[] args) {
		DoubleChain<String> doubleChain = new DoubleChain<String>();
		for (int i = 0; i < 4; i++) {
			doubleChain.add(i + "");
		}
		// 头插入
//		 doubleChain.addHead("head");
//		// 尾插入
//		 doubleChain.add("tail");
//		// 指定节点插入
//		 doubleChain.addSpecifyIndex("Specify", 1);
//		// 指定节点删除
//		 doubleChain.remove(3);
//		// 设置循环的初始节点
//		doubleChain.setCursor(0);
		int count = 0;
		System.out.println("######SIZE" + doubleChain.size() + "#######");
		while (doubleChain.hasNext()) {
			System.out.println("index:" + count + ",entry:"
					+ doubleChain.next());
			count++;
		}

		System.out.println(doubleChain.get(doubleChain.size() - 2));

	}

}

 

 

1
1
分享到:
评论

相关推荐

    java 单链表和双向链表的实现

    本话题主要探讨两种常用的数据结构——单链表和双向链表在Java中的实现,以及相关的操作,如在头部添加节点、在尾部添加节点、遍历、逆置和删除。 首先,我们来理解单链表和双向链表的基本概念。单链表是一种线性...

    JAVA实现链表_双向链表

    JAVA实现链表_双向链表

    Java实现双向链表

    用Java定义一个双向链表,实现链表的基本操作: 初始化、获取头结点、添加新元素、删除链表元素、 获取链表元素、查找链表元素、更新链表中某个元素、 判断链表是否为空、求链表元素个数、输出链表元素、清空链表。

    链表(数据结构--Java版)

    1. `DoublyLinkedClass.java` - 这个文件很可能包含了一个双向链表的实现。双向链表允许每个节点不仅知道下一个节点,还知道前一个节点。这样,我们可以向前和向后遍历链表,提供了更大的灵活性。 2. `...

    链表----链表构造

    根据节点间连接方式的不同,链表可以分为单向链表、双向链表和循环链表等。 #### 二、单向链表构造 本节将详细介绍单向链表的构造方法。单向链表是最简单的链表类型,其中每个节点仅包含一个指向其后继节点的指针...

    双向链表(java实现)

    在Java中实现双向链表,我们通常会创建一个表示链表节点的类(如`Node`),以及一个表示链表本身的类(如`MyLinkedList`)。`Node`类包含数据和两个引用,分别用于指向前一个节点和后一个节点。`MyLinkedList`类则...

    双端链表和双向链表Java代码

    本主题主要关注两种特殊类型的链表——双端链表(Double-ended LinkedList)和双向链表(Bidirectional LinkedList),并以Java语言实现为例进行讲解。 双端链表,也称为双链表,是一种允许在链表的两端进行插入和...

    JAVA双向链表反转实现

    以下是使用迭代方式实现双向链表反转的Java代码: ```java public void reverse() { if (head == null || head.next == null) { return; } Node current = head; Node previous = null; while (current != ...

    用java实现双向链表操作

    用java实现双向链表的完整操作,主要用到内部类实现。

    Java算法实例-双向链表操作

    本实例聚焦于Java中的一个重要数据结构——双向链表,它在很多场景下都有着广泛的应用。双向链表与单链表相比,其独特之处在于每个节点不仅包含指向下一个节点的指针,还包含指向前一个节点的指针,这使得在链表中的...

    单链表双向链表java实现

    在这个话题中,我们将深入探讨两种基本的线性数据结构——单链表和双向链表,并通过Java语言来实现它们。 单链表是一种线性数据结构,其中每个元素(称为节点)包含两个部分:数据域和指针域。数据域存储实际的数据...

    Java实现双向链表(两个版本)

    主要介绍了Java实现双向链表(两个版本)的相关资料,需要的朋友可以参考下

    Java有序非循环双向链表算法实例

    在Java编程中,有序非循环双向链表是一种重要的数据结构,它在许多复杂的数据操作和算法实现中扮演着核心角色。有序意味着链表中的元素按照特定的顺序排列,非循环则表示链表的首节点和尾节点之间没有链接,使得遍历...

    数据结构-链表 JAVA语言实现

    数据结构-链表 JAVA语言实现,包含单向链表、双向链表、循环链表的遍历、删除和插入 详细介绍:http://blog.csdn.net/z740852294/article/details/77369439

    Java语言编写的数据结构-链表实现

    单链表的扩展是双链表,也称为双向链表。每个节点不仅包含数据和指向下一个节点的引用,还包含一个指向前一个节点的引用。这种设计允许我们在链表中前后移动更加灵活,增加了插入和删除操作的效率,但同时也增加了...

    数据结构学习笔记-链表中的双向链表(JAVA)

    在Java中实现双向链表,我们可以创建一个名为`Node`的类来表示链表节点,其中包含`data`字段用于存储数据,`prev`字段用于存储前驱节点的引用,`next`字段用于存储后继节点的引用。接下来,我们需要一个`Doubly...

    Java双向链表的实现

    在本篇文章中,我们将探讨如何在Java中实现一个简单的双向链表。 首先,我们需要定义一个表示链表节点的类,通常命名为`Node`。这个类包含三个字段:`data`用于存储数据,`prev`指向前一个节点,`next`指向后一个...

    java 数据结构 链表

    在Java中,链表主要分为两种类型:单向链表和双向链表。单向链表的每个节点只能指向下一个节点,而双向链表的节点则可以同时指向前后两个节点,提供了更灵活的遍历方式。 1. 单向链表: - 单向链表的节点定义:...

Global site tag (gtag.js) - Google Analytics