要求:实现一个双向链表的倒置功能(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)。 双向链表的基本结构包括节点类,每个节点包含数据和指向前后节点的引用。通常,节点类会有如下的定义: ```python ...
根据给定文件的信息,本文将详细介绍双向链表的创建、插入、删除以及查询元素等相关算法。双向链表是一种常见的线性数据结构,在计算机科学中有着广泛的应用,它不仅支持向前遍历,还支持向后遍历,使得在链表中的...
通常,链表的反转可以分为三种类型:单链表的头尾反转、单链表的任意两个节点间的反转以及双向链表的反转。这里提到的程序"reverse.cpp"很可能实现的是单链表的头尾反转。 首先,我们需要定义链表节点的结构。在C++...
本文将深入探讨C/C++中单链表的操作,包括其定义、基本操作以及实现细节。 单链表是一种线性数据结构,每个元素称为节点,每个节点包含两个部分:数据域,存储实际信息;指针域,存储指向下一个节点的地址。链表的...
根据指针的方向,链表可以分为单向链表、双向链表和循环链表。 1. **单向链表**:每个节点只有一个指针,指向下一个节点。只能从头到尾进行遍历,不能反向遍历。插入和删除操作通常比数组快,因为只需要改变相邻...
8. **单链表与双向链表**:单链表的节点只包含一个指针,指向下一个节点;双向链表则包含两个指针,一个指向前一个节点,一个指向后一个节点。双向链表提供了更多的操作灵活性,但内存开销也更大。 9. **头插法与...
在实际应用中,原地倒置操作不仅限于链表,也可以应用于其他数据结构,如双向链表、栈等。不过,不同的数据结构可能需要不同的倒置策略。例如,对于数组,原地倒置可以通过双指针法实现,一个指针从头开始,另一个从...
单向链表的节点只能向前遍历,双向链表支持前后遍历,循环链表的最后一个节点指向第一个节点,形成一个环。 线性表与链表的主要操作包括插入、删除、查找等。在线性表中,插入操作通常需要移动后续元素,以空出位置...
2. **双向链表**:可以直接删除,时间复杂度为 `O(1)`。 3. **单向循环链表**:如果知道循环链表的尾结点,可以直接删除,时间复杂度为 `O(1)`;否则,需要遍历整个链表找到前驱结点,时间复杂度为 `O(n)`。 #### ...
通过理解和掌握这些概念,可以进一步探索更复杂的数据结构,如双向链表、循环链表、链式栈和链式队列等。在实际编程中,根据具体需求,可以对链表进行优化和扩展,以满足各种复杂的数据处理任务。
范例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 ∷相关函数...
lru缓存leetcode 学习和探索编程 C、C++、Python 探索领域: 1 数组 二分搜索、在滑动窗口中查找...,将二叉树转换为双向链表,打印树边界、连接同级兄弟、序列化/反序列化二叉树、连接所有兄弟、带父指针的中序后继 BS
LinkedHashSet由于内部维护了一个双向链表来维护插入顺序,因此可以保持元素的插入顺序。TreeSet内部通过红黑树算法对元素进行排序,可以按照自然排序(实现了Comparable接口的类)或者构造TreeSet时传入的...
链式存储的线性表分为单链表、循环单链表和双向链表。在单链表中,通过添加头节点,可以使得空表和非空表的操作统一,简化了实现。按位置查找在头节点处的效率为O(1),而按值查找的时间复杂度同样为O(n)。插入和删除...
单链表只有一个指向后继的指针,而双向链表还包含一个指向前驱的指针,这使得在链表中的前后移动更为灵活。 栈是一种后进先出(LIFO)的数据结构,常被比喻为一堆叠放的盘子。栈的主要操作有压栈(将元素添加到栈顶...
单链表每个节点只包含一个指向后继节点的指针,而双向链表则同时包含指向前驱节点和后继节点的指针。例如,以下代码展示了倒置单链表的方法: ```csharp public void Reverse() { Node<T> oldHead = Head; Node...
范例1-52 双向链表元素值的查询 129 ∷相关函数:GetElemP函数 1.3.22 稀疏矩阵的建立 136 范例1-53 稀疏矩阵的建立 136 ∷相关函数:Create函数 1.3.23 稀疏矩阵的删除 138 范例1-54 稀疏矩阵的删除 138 ∷...