`

双向链表倒置

 
阅读更多

 

要求:实现一个双向链表的倒置功能(1->2->3 变成 3->2->1)

代码: 

package com.mycom.test;

import java.util.LinkedList;

/**
 * 双向链表节点倒转
 *
 * @author guweiqiang
 * @date 2018年3月28日
 */
public class Test {
	
	/**
	 * 双向链表节点静态内部类
	 */
	public static class LinkedListNode {
		public LinkedListNode prev; // 前一个节点
		public LinkedListNode next; // 后一个节点
		public int value; // 当前节点值
		
		public LinkedListNode(int value) {
			this.value = value;
		}
	}
	
	/**
	 * 双向链表节点倒转
	 */
	private static LinkedListNode reverseNode(LinkedListNode node){
		LinkedListNode prev = null;
		LinkedListNode next = null;
		
		while(node!=null) {
			next = node.next;
			node.next = prev;
			node.prev = next;
			prev = node;
			node = next;
		}
		
		return prev;
	}
	
	/**
	 * 双向链表倒置
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static LinkedList<LinkedListNode> reverseList(LinkedList<LinkedListNode> linkedList){
		LinkedList<LinkedListNode> result = new LinkedList();
		for (int i=linkedList.size(); i>0; i--) {
			result.add(reverseNode(linkedList.get(i-1)));
		}
		return result;
	}

	/**
	 * main 测试
	 * @param args
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void main(String[] args) {
		// 原始双向链表
		LinkedList<LinkedListNode> linkedList = new LinkedList();
		// 第1种情况:节点是有序的
		for (int i=1; i<6; i++) {
			linkedList.add(new LinkedListNode(i));
		}
//		// 第2种情况:节点是无序的
//		linkedList.add(new LinkedListNode(2));
//		linkedList.add(new LinkedListNode(3));
//		linkedList.add(new LinkedListNode(1));
//		linkedList.add(new LinkedListNode(5));
//		linkedList.add(new LinkedListNode(4));
//		linkedList.add(new LinkedListNode(6));
		System.out.println("before reverse:");
		for(LinkedListNode node : linkedList) {
			System.out.print(node.value + " ");
		}
		
		// 倒转之后的双向链表
		LinkedList<LinkedListNode> result = reverseList(linkedList);
		System.out.println("\nafter reverse:");
		for(LinkedListNode node : result) {
			System.out.print(node.value + " ");
		}
	}

}

 以上是使用jdk自带的双向链表实现的,如果要自己实现一个双向链表呢?

 

自定义双向链表:

package com.mycom.test.linkedlist;

/**
 * 自定义双向链表
 *
 * @author guweiqiang
 * @date 2018年3月29日
 */
public class LinkedList<E> {
	
	private LinkedListNode<E> head; // 双向链表的头结点
	private int size; // 双向链表的大小
	private transient int modCount = 0; // 双向链表被修改的次数
	
	public LinkedList() {

	}
	
	public LinkedList(E e) {
		head = new LinkedListNode<E>(e); // 双向链表的头结点
		size++;
        modCount++;
	}
	
	/**
	 * 往双向链表里添加一个元素
	 * @param e 待添加的元素
	 * @return true:添加成功;false:添加失败
	 */
	public boolean add(E e) {
	    return addLast(e); // 默认将元素添加到双向链表的末尾
	}

	/**
	 * 在双向链表指定位置插入一个元素
	 * @param index 指定位置的下标
	 * @param e 待插入的元素
	 * @return true:插入成功;false:插入失败
	 */
	public boolean add(int index, E e) {
		LinkedListNode<E> node = this.getLinkedListNode(index); // 获取指定下标位置的节点
		addBefore(new LinkedListNode<E>(e), node); // 将上述节点添加到指定位置节点的前面
	    return true;
	}
	
	/**
	 * 往双向链表里添加第一个元素
	 * @param e 待添加的元素
	 * @return true:添加成功;false:添加失败
	 */
	public boolean addFirst(E e) {
		head = new LinkedListNode<E>(e);
        size++;
        modCount++;
	    return true;
	}

	/**
	 * 将元素添加到双向链表的最后
	 * @param e 待添加的元素
	 * @return true:添加成功;false:添加失败
	 */
	public boolean addLast(E e) {
		addBefore(new LinkedListNode<E>(e), head); // 将元素添加到头结点之前
	    return true;
	}

	/**
	 * 移除双向链表的元素(默认移除双向链表最后一个元素)
	 * @return true:移除成功;false:移除失败
	 */
	public boolean remove() {
		return removeLast();
	}
	
	/**
	 * 移除双向链表的尾结点元素
	 * @return true:移除成功;false:移除失败
	 */
	public boolean removeLast() {
		this.removeNode(head.prev);
		return true;
	}
	
	/**
	 * 获取指定位置的元素
	 * @param index 指定位置下标
	 * @return 元素
	 */
	public LinkedListNode<E> get(int index) {
	    return getLinkedListNode(index);
	}

	/**
	 * 判断双向链表中是否已经包含了该节点元素
	 * @return true:包含;false:不包含
	 */
	public boolean contain(LinkedListNode<E> e) {
        if (e == null) {
        	// 从链表的表头开始查找,如果找到了就返回true
            for (LinkedListNode<E> node = head; node != null; node = node.next) {
                if (node.e == null) { // 找到为null的元素
                	return true;
                }
            }
        } else {
        	// 从链表的表头开始查找,如果找到了就返回true
            for (LinkedListNode<E> node = head; node != null; node = node.next) {
                if (e.equals(node.e)) { // 两个元素的equal比较如果为true,则返回true
                    return true;
                }
            }
        }
        return false;
	}
	
	/**
	 * 清空双向链表
	 */
	public void clear() {
		for (LinkedListNode<E> node = head; node != null; node = node.next) {
			node.e = null;
			node.next = null;
			node.prev = null;
        }
        head = null;
        size = 0;
        modCount++;
	}
	
	/**
	 * 获取双向链表的大小
	 * @return 双向链表的大小
	 */
	public int size() {
	    return this.size;
	}
	
	/**
	 * 打印链表里的元素
	 */
	public String toString(LinkedList<E> list) {
		StringBuffer str = new StringBuffer("");
		for (int i=0; i<list.size; i++) {
			str.append(list.get(i).e.toString() + " ");
		}
		return str.toString();
	}
	
	/**
	 * 双向链表所有节点元素倒转
	 * @param oldList 倒转之前的linkedList
	 * @return 倒转之后的linkedList
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public LinkedList<E> reverseList(LinkedList<E> oldList){
		LinkedList<E> resultList = new LinkedList(oldList.get(oldList.size()-1).e);
		for (int i=oldList.size()-1; i>0; i--) {
			resultList.add(this.reverseNode(oldList.get(i-1)).e);
		}
		return resultList;
	}
	
	/**
	 * 双向链表节点倒转
	 * @param node 待倒转的节点
	 */
	private LinkedListNode<E> reverseNode(LinkedListNode<E> node){
		LinkedListNode<E> prev = null;
		LinkedListNode<E> next = null;
		
		next = node.next;
		node.next = prev;
		node.prev = next;
		prev = node;
		node = next;
		
		return prev;
	}
	
	/**
	 * 在当前节点前面插入一个节点
	 * @param newNode 要添加的新节点
	 * @param node 当前节点
	 */
	private void addBefore(LinkedListNode<E> newNode, LinkedListNode<E> node) {
	    newNode.next = node;
	    newNode.prev = node.prev;
	    newNode.next.prev = newNode;
	    newNode.prev.next = newNode;
	    size++;
        modCount++;
	}
	
	/**
	 * 在当前节点后面插入一个节点
	 * @param newNode 要添加的新节点
	 * @param node 当前节点
	 */
	@SuppressWarnings("unused")
	private void addAfter(LinkedListNode<E> newNode, LinkedListNode<E> node) {
	    newNode.prev = node;
	    newNode.next = node.next;
	    newNode.next.prev = newNode;
	    newNode.prev.next = newNode;
	    size++;
        modCount++;
	}
	
	/**
	 * 移除指定位置的节点元素
	 * @param node 待移除的节点
	 */
	private void removeNode(LinkedListNode<E> node) {
		node.prev.next = node.next;
	    node.next.prev = node.prev;
	    node.prev = null;
	    node.next = null;
	    size--;
        modCount++;
	}
	
	/**
	 * 获取双向链表中指定位置的元素
	 * @param index 指定位置下标
	 * @return 元素
	 */
	private LinkedListNode<E> getLinkedListNode(int index) {
		// 判断下标是否越界,如果越界则抛出异常
		if(index<0 || index>size) {
			throw new IndexOutOfBoundsException();
		}
		
		// 从链表的表头开始遍历,遍历每一个节点,直到下标为index所在的元素
		LinkedListNode<E> node = head;
		for(int i=0; i<index; i++) {
			node = node.next;
		}
		
		return node;
	}
	
	/**
	 * 双向链表节点静态内部类
	 */
	public static class LinkedListNode<E> {
		public LinkedListNode<E> prev = this; // 前一个节点
		public LinkedListNode<E> next = this; // 后一个节点
		public E e; // 当前节点元素
		
		public LinkedListNode(E e) {
			this.e = e;
		}
	}

}

 测试用例:

package com.mycom.test.linkedlist;

/**
 * 测试双向链表节点倒转
 *
 * @author guweiqiang
 * @date 2018年3月29日
 */
public class Test1 {
	
	/**
	 * 测试有序节点倒转
	 */
	private void testOrderNum(){
		// 原始双向链表,初始化head节点为1
		LinkedList<Integer> linkedList = new LinkedList<Integer>(1);
		// 节点是有序的
		for (int i=1; i<5; i++) {
			linkedList.add(Integer.valueOf(i+1));
		}
		System.out.println("before reverse:");
		for (int i=0; i<linkedList.size(); i++) {
			System.out.print(linkedList.get(i).e.intValue() + " ");
		}
		
		// 倒转之后的双向链表
		LinkedList<Integer> resultList = new LinkedList<Integer>().reverseList(linkedList);
		System.out.println("\nafter reverse:");
		for (int i=0; i<resultList.size(); i++) {
			System.out.print(resultList.get(i).e.intValue() + " ");
		}
	}
	
	/**
	 * 测试无序节点倒转
	 */
	private void testNonOrderNum(){
		// 原始双向链表,初始化head节点为2
		LinkedList<Integer> linkedList = new LinkedList<Integer>(2);
		// 节点是无序的
		linkedList.add(1);
		linkedList.add(3);
		linkedList.add(5);
		linkedList.add(4);
		System.out.println("before reverse:");
		for (int i=0; i<linkedList.size(); i++) {
			System.out.print(linkedList.get(i).e.intValue() + " ");
		}
		// 倒转之后的双向链表
		LinkedList<Integer> resultList = new LinkedList<Integer>().reverseList(linkedList);
		System.out.println("\nafter reverse:");
		for (int i=0; i<resultList.size(); i++) {
			System.out.print(resultList.get(i).e.intValue() + " ");
		}
	}
	
	/**
	 * main 
	 * @param args
	 */
	public static void main(String[] args) {
		Test1 test = new Test1();
		test.testOrderNum();
		test.testNonOrderNum();
	}

}

 

 

 

分享到:
评论

相关推荐

    实现一个双向链表的倒置功能(1->2->3 变成 3->2->1)

    在本题中,我们需要实现一个功能,将给定的双向链表(1-&gt;2-&gt;3)倒置,使其变为(3-&gt;2-&gt;1)。 双向链表的基本结构包括节点类,每个节点包含数据和指向前后节点的引用。通常,节点类会有如下的定义: ```python ...

    双向链表的建立,插入,删除,寻找元素等算法

    根据给定文件的信息,本文将详细介绍双向链表的创建、插入、删除以及查询元素等相关算法。双向链表是一种常见的线性数据结构,在计算机科学中有着广泛的应用,它不仅支持向前遍历,还支持向后遍历,使得在链表中的...

    倒置——链表(附源代码)

    通常,链表的反转可以分为三种类型:单链表的头尾反转、单链表的任意两个节点间的反转以及双向链表的反转。这里提到的程序"reverse.cpp"很可能实现的是单链表的头尾反转。 首先,我们需要定义链表节点的结构。在C++...

    C/C++单链表的一些操作

    本文将深入探讨C/C++中单链表的操作,包括其定义、基本操作以及实现细节。 单链表是一种线性数据结构,每个元素称为节点,每个节点包含两个部分:数据域,存储实际信息;指针域,存储指向下一个节点的地址。链表的...

    链表的基本操作,插入删除查找等

    根据指针的方向,链表可以分为单向链表、双向链表和循环链表。 1. **单向链表**:每个节点只有一个指针,指向下一个节点。只能从头到尾进行遍历,不能反向遍历。插入和删除操作通常比数组快,因为只需要改变相邻...

    c语言链表的基本操作.rar

    8. **单链表与双向链表**:单链表的节点只包含一个指针,指向下一个节点;双向链表则包含两个指针,一个指向前一个节点,一个指向后一个节点。双向链表提供了更多的操作灵活性,但内存开销也更大。 9. **头插法与...

    数据结构完整的原地倒置代码

    在实际应用中,原地倒置操作不仅限于链表,也可以应用于其他数据结构,如双向链表、栈等。不过,不同的数据结构可能需要不同的倒置策略。例如,对于数组,原地倒置可以通过双指针法实现,一个指针从头开始,另一个从...

    线性表和链表的基本算法

    单向链表的节点只能向前遍历,双向链表支持前后遍历,循环链表的最后一个节点指向第一个节点,形成一个环。 线性表与链表的主要操作包括插入、删除、查找等。在线性表中,插入操作通常需要移动后续元素,以空出位置...

    数据分析,链表相关复习

    2. **双向链表**:可以直接删除,时间复杂度为 `O(1)`。 3. **单向循环链表**:如果知道循环链表的尾结点,可以直接删除,时间复杂度为 `O(1)`;否则,需要遍历整个链表找到前驱结点,时间复杂度为 `O(n)`。 #### ...

    数据结构实现链表

    通过理解和掌握这些概念,可以进一步探索更复杂的数据结构,如双向链表、循环链表、链式栈和链式队列等。在实际编程中,根据具体需求,可以对链表进行优化和扩展,以满足各种复杂的数据处理任务。

    数据结构(王)c元代码

    范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷相关函数...

    数据结构算法实现(严蔚敏版配套实现程序)

    范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷相关函数...

    数据结构 严蔚敏 代码

    范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷相关函数...

    数据结构算法实现(严蔚敏版配套实现程序)

    范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷相关函数...

    lrucacheleetcode-Codes:学习编程

    lru缓存leetcode 学习和探索编程 C、C++、Python 探索领域: 1 数组 二分搜索、在滑动窗口中查找...,将二叉树转换为双向链表,打印树边界、连接同级兄弟、序列化/反序列化二叉树、连接所有兄弟、带父指针的中序后继 BS

    Java集合框架常见面试题夜间阅读版.pdf

    LinkedHashSet由于内部维护了一个双向链表来维护插入顺序,因此可以保持元素的插入顺序。TreeSet内部通过红黑树算法对元素进行排序,可以按照自然排序(实现了Comparable接口的类)或者构造TreeSet时传入的...

    2、线性结构1

    链式存储的线性表分为单链表、循环单链表和双向链表。在单链表中,通过添加头节点,可以使得空表和非空表的操作统一,简化了实现。按位置查找在头节点处的效率为O(1),而按值查找的时间复杂度同样为O(n)。插入和删除...

    数据结构与算法分析

    单链表只有一个指向后继的指针,而双向链表还包含一个指向前驱的指针,这使得在链表中的前后移动更为灵活。 栈是一种后进先出(LIFO)的数据结构,常被比喻为一堆叠放的盘子。栈的主要操作有压栈(将元素添加到栈顶...

    数据结构之线性结构和非线性结构.pdf

    单链表每个节点只包含一个指向后继节点的指针,而双向链表则同时包含指向前驱节点和后继节点的指针。例如,以下代码展示了倒置单链表的方法: ```csharp public void Reverse() { Node&lt;T&gt; oldHead = Head; Node...

    C语言通用范例开发金典.part2.rar

    范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷...

Global site tag (gtag.js) - Google Analytics