数据结构学习----线性表的链式表示之循环双链表(Java实现)
2014-10-16 13:49 雪夜&流星 阅读(966) 评论(0) 编辑 收藏 举报线性表接口LList:
package com.clarck.datastructure.dlinked; /** * 线性表接口LList,描述线性表抽象数据类型,泛型参数T表示数据元素的数据类型 * * @author clarck * */ public interface LList<T> { /** * 判断线性表是否空 * @return */ boolean isEmpty(); /** * 返回线性表长度 * @return */ int length(); /** * 返回第i(i≥0)个元素 * @param i * @return */ T get(int i); /** * 设置第i个元素值为x * @param i * @param x */ void set(int i, T x); /** * 插入x作为第i个元素 * @param i * @param x */ void insert(int i, T x); /** * 在线性表最后插入x元素 * @param x */ void append(T x); /** * 删除第i个元素并返回被删除对象 * @param i * @return */ T remove(int i); /** * 删除线性表所有元素 */ void removeAll(); /** * 查找,返回首次出现的关键字为key元素 * @param key * @return */ T search(T key); }
双链表结点类:
package com.clarck.datastructure.dlinked; /** * 双链表结点类 * * @author clarck * */ public class DLinkNode<T> { /** * 数据元素 */ public T data; /** * pred指向前驱结点,next指向后继结点 */ public DLinkNode<T> pred, next; /** * 构造节点,data指定元素,pred指向前驱节点,next指向后继节点 */ public DLinkNode(T data, DLinkNode<T> pred, DLinkNode<T> next) { this.data = data; this.pred = pred; this.next = next; } /** * 默认构造器 */ public DLinkNode() { this(null, null, null); } }
循环双链表:
package com.clarck.datastructure.dlinked; /** * 循环双链表 * * @author clarck * * @param <T> */ public class CirDoublyLinkedList<T> implements LList<T> { /** * 头节点 */ public DLinkNode<T> head; /** * 默认构造方法,构造空循环双链表 * * 创建头结点,3个域值均为null */ public CirDoublyLinkedList() { this.head = new DLinkNode<T>(); this.head.pred = this.head; this.head.next = this.head; } /** * 由指定数组中的多个对象构造循环双链表,采用尾插入构造循环双链表 * * @param element */ public CirDoublyLinkedList(T[] element) { // 创建空循环双链表,只有头结点 this(); DLinkNode<T> rear = this.head; for (int i = 0; i < element.length; i++) { rear.next = new DLinkNode<T>(element[i], rear, this.head); // 尾插入 rear = rear.next; } this.head.pred = rear; } /** * 深拷贝构造方法,复制循环双链表 * * @param list */ public CirDoublyLinkedList(CirDoublyLinkedList<T> list) { // 创建空循环双链表,只有头结点 this(); DLinkNode<T> rear = this.head; for (DLinkNode<T> p = list.head.next; p != list.head; p = p.next) { rear.next = new DLinkNode<T>(p.data, rear, this.head); rear = rear.next; } this.head.pred = rear; } /** * 判断循环双链表是否空 */ @Override public boolean isEmpty() { return this.head.next == this.head; } /** * 插入第i(≥0)个元素值为x。若x==null,不插入。 若i<0,插入x作为第0个元素;若i大于表长,插入x作为最后一个元素。O(n) */ @Override public int length() { int i = 0; for (DLinkNode<T> p = this.head.next; p != this.head; p = p.next) { i++; } return i; } /** * 返回第i(≥0)个元素,若i<0或大于表长则返回null, */ @Override public T get(int i) { if (i >= 0) { DLinkNode<T> p = this.head.next; for (int j = 0; p != this.head && j < i; j++) { p = p.next; } // p指向第i个结点 if (p != null) { return p.data; } } return null; } /** * 设置第i(≥0)个元素值为x。若i<0或大于表长则抛出序号越界异常;若x==null,不操作。O(n) */ @Override public void set(int i, T x) { if (x == null) return; DLinkNode<T> p = this.head.next; for (int j = 0; p != this.head && j < i; j++) { p = p.next; } // p指向第i个结点 if (i >= 0 && p != null) { p.data = x; } else { throw new IndexOutOfBoundsException(i + ""); } } /** * 插入第i(≥0)个元素值为x。若x==null,不插入。 若i<0,插入x作为第0个元素;若i大于表长,插入x作为最后一个元素。O(n) */ @Override public void insert(int i, T x) { if (x == null) return; DLinkNode<T> p = this.head; // 寻找插入位置 循环停止时,p指向第i-1个结点 for (int j = 0; p.next != this.head && j < i; j++) { p = p.next; } // 插入在p结点之后,包括头插入、中间插入 DLinkNode<T> q = new DLinkNode<T>(x, p, p.next); p.next.pred = q; p.next = q; } /** * 在循环双链表最后添加结点,O(1) */ @Override public void append(T x) { if (x == null) return; // 插入在头结点之前,相当于尾插入 DLinkNode<T> q = new DLinkNode<T>(x, head.pred, head); head.pred.next = q; head.pred = q; } /** * 删除第i(≥0)个元素,返回被删除对象。若i<0或i大于表长,不删除,返回null。O(n) */ @Override public T remove(int i) { if (i >= 0) { DLinkNode<T> p = this.head.next; // 定位到待删除结点 for (int j = 0; p != this.head && j < i; j++) { p = p.next; } if (p != head) { // 获得原对象 T old = p.data; // 删除p结点自己 p.pred.next = p.next; p.next.pred = p.pred; return old; } } return null; } /** * 删除循环双链表所有元素 */ @Override public void removeAll() { this.head.pred = this.head; this.head.next = this.head; } /** * 顺序查找关键字为key元素,返回首次出现的元素,若查找不成功返回null * key可以只包含关键字数据项,由T类的equals()方法提供比较对象相等的依据 */ @Override public T search(T key) { if (key == null) return null; for (DLinkNode<T> p = this.head.next; p != this.head; p = p.next) if (key.equals(p.data)) return p.data; return null; } /** * 返回循环双链表所有元素的描述字符串,循环双链表遍历算法,O(n) */ @Override public String toString() { String str = "("; for (DLinkNode<T> p = this.head.next; p != this.head; p = p.next) { str += p.data.toString(); if (p.next != this.head) str += ","; } return str + ")"; // 空表返回() } /** * 比较两条循环双链表是否相等,覆盖Object类的equals(obj)方法 */ @SuppressWarnings("unchecked") public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof CirDoublyLinkedList)) return false; DLinkNode<T> p = this.head.next; CirDoublyLinkedList<T> list = (CirDoublyLinkedList<T>) obj; DLinkNode<T> q = list.head.next; while (p != head && q != list.head && p.data.equals(q.data)) { p = p.next; q = q.next; } return p == head && q == list.head; } }
循环双链表 测试类:
package com.clarck.datastructure.dlinked; /** * 循环双链表 测试类 * * @author clarck * */ public class CirDoublyLinkedList_test { /** * 返回产生n个随机数的数组 * * @param n * @return */ public static Integer[] random(int n) { Integer[] elements = new Integer[n]; for (int i = 0; i < n; i++) elements[i] = (int) (Math.random() * 100); // 产生随机数 return elements; } public static void main(String args[]) { CirDoublyLinkedList<Integer> list1 = new CirDoublyLinkedList<Integer>( random(5)); System.out.print("list1: " + list1.toString() + ","); list1.insert(-1, -1); // 插入位置容错 list1.insert(0, 0); list1.insert(6, 6); list1.insert(100, 100); // 插入位置容错 list1.set(3, new Integer((int) (list1.get(3).intValue() + 100))); System.out.println("插入后: " + list1.toString()); list1.remove(0); list1.remove(3); list1.remove(100); // 序号越界,没删除 System.out.println("删除后: " + list1.toString()); CirDoublyLinkedList<Integer> list2 = new CirDoublyLinkedList<Integer>( list1);// 深拷贝 System.out.println("list2: " + list2.toString()); } }
运行结果:
list1: (53,75,30,97,56),插入后: (0,-1,53,175,30,97,6,56,100) 删除后: (-1,53,175,97,6,56,100) list2: (-1,53,175,97,6,56,100)
源码:https://github.com/clarck/DataStructure/tree/master/DLinkedList/src/com/clarck/datastructure/dlinked
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本