Java中双链表的操作

绝地灬酷狼 2023-10-05 01:53 53阅读 0赞

Java中双链表的操作

  1. 双链表根据内容添加结点
  2. 双链表根据内容删除结点
  3. 双链表根据内容修改(新内容替换旧内容)
  4. 双链表根据内容查找结点索引 索引从0开始
  5. 根据下标添加结点内容
  6. 根据下标删除
  7. 根据下标查找值
  8. 根据下标修改值

    public class DBNode {

    1. // 双向链表和单链表
    2. // 三个域
    3. // 值域
    4. String value;
    5. // 前结点
    6. DBNode pre;
    7. // 后结点
    8. DBNode next;
    9. // 构造方法
    10. public DBNode(String value, DBNode pre, DBNode next) {
    11. this.value = value;
    12. this.pre = pre;
    13. this.next = next;
    14. }
    15. // 重写
    16. @Override
    17. public String toString() {
    18. return "{" +
    19. "value='" + value + '\'' +
    20. ", next=" + next +
    21. '}';
    22. }

    }

    public class MyDBLinked {

    1. // 头结点
    2. private DBNode top;
    3. // 尾结点
    4. private DBNode end;
    5. private int size;
    6. /**
    7. * 双链表根据内容添加结点
    8. *
    9. * @param str 添加内容
    10. *
    11. * @return 添加成功返回true,失败则返回false
    12. */
    13. public boolean add(String str) {
    14. // 判断原本的链表是不是空链表
    15. if (top == null) {
    16. // 原本的链表为空
    17. top = new DBNode(str, null, null);
    18. // 此时链表只有一个结点,尾结点头结点均为同一个结点;
    19. end = top;
    20. // 链表长度加一
    21. size++;
    22. return true;
    23. }
    24. // 程序走到这里就代表原本的链表不为空
    25. // new一个链表结点,新结点的前驱结点为end;
    26. DBNode node = new DBNode(str, end, null);
    27. // 在双链表的末尾加上node结点
    28. end.next = node;
    29. end = node;
    30. size++;
    31. return true;
    32. }
    33. /**
    34. * 双链表根据内容删除结点
    35. *
    36. * @param str 需要删除的内容
    37. *
    38. * @return 返回删除结点的内容
    39. */
    40. public String remove(String str) {
    41. // 判断双链表是否为空
    42. if (size == 0) {
    43. // 为空则抛出异常
    44. throw new RuntimeException("双链表为空");
    45. }
    46. // 判断删除的结点是否为头结点
    47. if (top.value.equals(str)) {
    48. // 删除头结点
    49. top = top.next;
    50. // 如果双链表原本就一个结点
    51. if (size == 1) {
    52. end = null;
    53. } else {
    54. // 只有原本的链表多于一个结点的时候,才需要把后移的top的前指向去除
    55. top.pre = null;
    56. }
    57. size--;
    58. return str;
    59. }
    60. // 删除的不是头结点
    61. DBNode mid = top;
    62. // 对结点进行遍历判断,mid=top 即mid为头结点
    63. // mid.next为当前结点
    64. while (mid.next != null && !mid.next.value.equals(str)) {
    65. mid = mid.next;
    66. }
    67. // 程序走到这里,说明结点为尾结点,或者是符合删除要求的结点,或者是未找到符合删除条件的结点
    68. if (mid.next == null) {
    69. // 未找到结点
    70. return null;
    71. }
    72. // 单独对尾结点进行删除处理
    73. // mid.next.next即为当前结点的下一个结点
    74. // mid.next.next == null 即当前结点mid.next为尾结点
    75. if (mid.next.next == null) {
    76. //即要删除的结点为尾结点
    77. // 先记录尾结点旧值
    78. String oldValue = mid.next.value;
    79. // 把当前的尾结点置为null
    80. mid.next = null;
    81. // 当前尾结点mid.next已被置为null,所以需要把尾结点标记迁移
    82. end = mid;
    83. // 整体size-1;
    84. size--;
    85. // 返回删除的值
    86. return oldValue;
    87. }
    88. // 程序走到这,说明mid.next一定就是被找到的符合删除条件的结点
    89. // mid则为符合删除条件结点的前一个结点
    90. // 要删除的目标结点
    91. DBNode targetNode = mid.next;
    92. // 要删除结点的前驱结点的后继结点=要删除结点的后继结点
    93. targetNode.pre.next = targetNode.next;
    94. // 要删除结点的后继结点的前驱结点=要删除结点的前驱结点
    95. targetNode.next.pre = targetNode.pre;
    96. // 到此为止,结点删除成功
    97. size--;
    98. return targetNode.value;
    99. }
    100. /**
    101. * 双链表根据内容修改(新内容替换旧内容)
    102. *
    103. * @param oldStr 旧结点内的内容
    104. * @param newStr 修改之后的内容
    105. *
    106. * @return 修改成功返回true,失败则返回false
    107. */
    108. public boolean set(String oldStr, String newStr) {
    109. // 参数校验
    110. // 判断双链表是否为空
    111. if (top == null) {
    112. throw new RuntimeException("Linked is null");
    113. }
    114. // 声明遍历链表时的记录结点mid
    115. DBNode mid = top;
    116. //对结点进行遍历,如果结点不为空,即不为尾结点
    117. //或结点不符合替换条件,就继续向后遍历链表
    118. while (mid != null && !mid.value.equals(oldStr)) {
    119. mid = mid.next;
    120. }
    121. // 程序走到这里,说明此时的结点为以下两种情况之一
    122. // 1,mid为null,即未找到符合修改条件的结点
    123. // 2,结点符合修改条件
    124. // 先对mid为null,即未找到符合修改条件的结点 进行判断
    125. if (mid == null) {
    126. // 未找到符合修改条件的结点
    127. return false;
    128. }
    129. // 此时只剩下结点符合修改条件这一种情况,直接替换修改即可
    130. mid.value = newStr;
    131. return true;
    132. }
    133. /**
    134. * 双链表根据内容查找结点索引 索引从0开始
    135. *
    136. * @return 返回结点的索引
    137. */
    138. public int getIndex(String str) {
    139. //判断链表是否为空
    140. if (top == null) {
    141. throw new RuntimeException("Linked is null");
    142. }
    143. // 记录结点
    144. DBNode mid = top;
    145. //定义变量,记录索引值
    146. int count = 0;
    147. // 对结点进行遍历,直到查到尾结点或者找到符合要求的结点
    148. while (mid != null && !mid.value.equals(str)) {
    149. mid = mid.next;
    150. count++;
    151. }
    152. // 未找到符合要求的结点
    153. if (mid == null) {
  1. return -1;
  2. }
  3. // 程序走到这里,说明已经找到符合要求的结点,返回索引记录值
  4. return count;
  5. }
  6. /**
  7. * 根据下标添加结点内容
  8. *
  9. * @param index 添加元素位置
  10. * @param str 添加内容
  11. *
  12. * @return 添加成功返回true,失败则返回false
  13. */
  14. public boolean addByIndex(int index, String str) {
  15. // 校验需要添加的位置是否合法
  16. if (index > size || index < 0) {
  17. throw new RuntimeException("index is Illegal");
  18. }
  19. // 参数合法,继续执行
  20. // 创建需要添加的结点的对象
  21. DBNode dbNode = new DBNode(str, null, null);
  22. // 需要添加的结点是头结点,即index为0,size=0
  23. if (index == 0) {
  24. // 新结点的下一个结点指向原结点的头结点
  25. dbNode.next = top;
  26. if (top != null) {
  27. // 如果原链表不为空,原结点的前驱结点指向新节点
  28. top.pre = dbNode;
  29. } else {
  30. // 原链表为空,尾结点指向新节点
  31. end = dbNode;
  32. }
  33. // 把头结点标记前移
  34. top = dbNode;
  35. // 结点长度+1
  36. size++;
  37. return true;
  38. }
  39. // 程序既然执行到这里,size就不会为0
  40. // 如果需要添加的结点为尾结点,即index=size
  41. if (index == size) {
  42. // 新结点的前驱指向原旧结点
  43. dbNode.pre = end;
  44. // 原尾结点的后继指向该添加到尾部的结点
  45. end.next = dbNode;
  46. // 尾结点后移
  47. end = dbNode;
  48. size++;
  49. return true;
  50. }
  51. // 程序走到这里就说明需要添加的位置在头结点和尾结点之间
  52. // mid用来标记要添加位置的前一个位置
  53. DBNode mid = top;
  54. // 声明count记录链表位置
  55. int count = 1;
  56. // 对链表进行遍历
  57. while (index != count) {
  58. mid = mid.next;
  59. count++;
  60. }
  61. // 当index==count时,就会跳出循环,即满足添加条件
  62. // 把新结点添加到mid和mid.next中间
  63. dbNode.next = mid.next;
  64. dbNode.pre = mid;
  65. dbNode.next.pre = dbNode;
  66. mid.next = dbNode;
  67. size++;
  68. return true;
  69. }
  70. /**
  71. * 根据索引删除
  72. *
  73. * @param index 需要删除位置的索引
  74. *
  75. * @return 返回被删除的内容
  76. */
  77. public String removeByIndex(int index) {
  78. // 对链表进行参数校验
  79. if (top == null) {
  80. throw new RuntimeException("linked is null");
  81. }
  82. // 校验要查找的索引是否合法(索引从0开始)
  83. if (index < 0 || index > size - 1) {
  84. throw new RuntimeException("param is Illegal");
  85. }
  86. //为提高查找效率,获取元素所属的范围
  87. int midIndex = size / 2;
  88. // 判断需要查找元素所属的范围
  89. // 声明一个空结点
  90. DBNode mid = null;
  91. if (midIndex > index) {
  92. // 要删除的元素在链表的前半部分
  93. // 头结点
  94. mid = top;
  95. int count = 0;
  96. while (count != index) {
  97. count++;
  98. mid = mid.next;
  99. }
  100. } else {
  101. // 要删除的元素在后半部分
  102. mid = end;
  103. int count = size - 1;
  104. while (count != index) {
  105. count--;
  106. mid = mid.pre;
  107. }
  108. }
  109. // mid 就是要删除的结点
  110. // 如果mid是头结点
  111. if (mid == top) {
  112. // 使头结点后移
  113. top = top.next;
  114. // 如果后移之后结点变为null
  115. if (top == null) {
  116. // 代表原链表仅有一个结点
  117. end = null;
  118. } else {
  119. // 代表链表不仅仅只有一个结点
  120. top.pre = null;
  121. }
  122. size--;
  123. return mid.value;
  124. }
  125. // 如果删除的是尾结点
  126. if (mid == end) {
  127. end = end.pre;
  128. // 链表和原尾结点断开连接
  129. end.next = null;
  130. size--;
  131. return mid.value;
  132. }
  133. // 删除的既不是头结点,也不是尾结点
  134. mid.pre.next = mid.next;
  135. mid.next.pre = mid.pre;
  136. size--;
  137. return mid.value;
  138. }
  139. /**
  140. * 根据下标查找值
  141. * @param index 提供的下标
  142. * @return 返回查找到的值
  143. */
  144. public String get(int index){
  145. // 参数效验
  146. if (top == null) {
  147. throw new IllegalArgumentException("mylinked is null");
  148. }
  149. if (index < 0 || index > size - 1) {
  150. throw new IllegalArgumentException("param is Illegal");
  151. }
  152. // 获取中间位置下标
  153. int midIndex = size/2;
  154. DBNode mid = null;
  155. if (index < midIndex){
  156. // 查找值在前半部分
  157. mid = top;
  158. int tag = 0;
  159. // 从头结点向后遍历
  160. while (tag != index){
  161. mid = mid.next;
  162. tag++;
  163. }
  164. } else {
  165. // 查找值在后半部分
  166. mid = end;
  167. int tag = size - 1;
  168. // 从尾结点向前遍历
  169. while (tag != index){
  170. mid = mid.pre;
  171. tag--;
  172. }
  173. }
  174. return mid.value;
  175. }
  176. /**
  177. * 根据下标修改值
  178. * @param index 需要修改的下标位置
  179. * @param str 修改的新值
  180. * @return 被覆盖的旧值
  181. */
  182. public String set(int index, String str){
  183. // 参数效验
  184. if (top == null) {
  185. throw new IllegalArgumentException("mylinked is null");
  186. }
  187. if (index < 0 || index > size - 1) {
  188. throw new IllegalArgumentException("param is Illegal");
  189. }
  190. // 获取中间位置下标
  191. int midIndex = size/2;
  192. DBNode mid = null;
  193. if (index < midIndex){
  194. // 查找值在前半部分
  195. mid = top;
  196. int tag = 0;
  197. // 从头结点向后遍历
  198. while (tag != index){
  199. mid = mid.next;
  200. tag++;
  201. }
  202. } else {
  203. // 查找值在后半部分
  204. mid = end;
  205. int tag = size - 1;
  206. // 从尾结点向前遍历
  207. while (tag != index){
  208. mid = mid.pre;
  209. tag--;
  210. }
  211. }
  212. // 保存旧值
  213. String oldValue = mid.value;
  214. // 替换新值
  215. mid.value = str;
  216. return oldValue;
  217. }
  218. @Override
  219. public String toString() {
  220. return "DemoLinked1{" +
  221. "top=" + top +
  222. ", end=" + end +
  223. ", size=" + size +
  224. '}';
  225. }
  226. }

发表评论

表情:
评论列表 (有 0 条评论,53人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java操作

    Java中双链表的操作 1. 双链表根据内容添加结点 2. 双链表根据内容删除结点 3. 双链表根据内容修改(新内容替换旧内容) 4. 双链表根据内容查找结点索引

    相关 基本操作

     双端链表:双端链表和单向链表大体上是一样的,不同的是,单向链表在表尾部分插入元素时,需要从头结点一直遍历到尾结点才能进行插入操作,这样难免有些繁琐。因此如果加入一个对尾结点的