数据结构--单向链表

举报
brucexiaogui 发表于 2021/12/29 23:46:53 2021/12/29
【摘要】 数据结构--单向链表 一、单链表描述 单链表 这是链表中结构最简单的,一个单链表的节点(Node)分为两部分,第一个部分保存或者显示节点的信息,另一个部分存储的是下一个节点的地址,最后一个节点存储的地址的部分指向的是空值。 单链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始访问,一直访问到需要的位置。而插入...

数据结构--单向链表

一、单链表描述

单链表

这是链表中结构最简单的,一个单链表的节点(Node)分为两部分,第一个部分保存或者显示节点的信息,另一个部分存储的是下一个节点的地址,最后一个节点存储的地址的部分指向的是空值。

单链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始访问,一直访问到需要的位置。而插入一个节点,对于单链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头结点,next节点指向原头节点即可,删除一个节点,我们将该节点的前一个节点的next指向该节点的下一个节点。

单链表插入新节点图

删除节点图

二、链表结构优缺点

1、为什么单向链表的增删效率高

因为链表每个元素存储的空间是没有顺序的,删除或者添加某个元素,只需要让该节点指针重新指向下一个节点即可。

数组因为是连续的地址内存,需要移动元素位置,所以数组增伤效率较低。

2、为什么单向链表查询效率较低

单向链表的每个元素在空间的存储位置上没有规律,也没有顺序。那么在查找某个元素的时候必须从头节点挨着往下找,直到找到为止。

三、单向列表实现


  
  1. public class SingleLinkedList {
  2. private int size; //链表节点的个数
  3. private Node head;
  4. public SingleLinkedList(){
  5. size = 0;
  6. head = null;
  7. }
  8. private class Node{
  9. private Object data; //每个节点的数据
  10. private Node next; //每个节点指向下一个节点的连接
  11. public Node(Object data){
  12. this.data = data;
  13. }
  14. }
  15. //在链表头部添加元素
  16. public Object addHead(Object obj){
  17. Node newhead = new Node(obj);
  18. if(size == 0){
  19. head = newhead;
  20. }else{
  21. newhead.next = head;
  22. head = newhead;
  23. }
  24. size++;
  25. return obj;
  26. }
  27. //在单链表头部进行删除
  28. public Object delHead(){
  29. Object obj = head.data;
  30. head = head.next;
  31. size--;
  32. return obj;
  33. }
  34. //查找返回指定节点,找不到,返回Null
  35. public Node FindNode(Object obj){
  36. Node currnet = head;
  37. for(int i = 0; i < size; i++){
  38. if(obj.equals(currnet.data)){
  39. return currnet;
  40. }else{
  41. currnet = currnet.next;
  42. }
  43. }
  44. return null;
  45. }
  46. //删除指定元素,成功返回ture
  47. public boolean delete(Object obj){
  48. if(size == 0){
  49. return false;
  50. }
  51. Node current = head;
  52. Node previous = head;
  53. while(!current.data.equals(obj)){
  54. if(current.next == null){
  55. return false;
  56. }else{
  57. previous = current;
  58. current = current.next;
  59. }
  60. }
  61. //如果删除的节点是第一个节点
  62. if(current == head){
  63. head = current.next;
  64. size--;
  65. }else{
  66. //删除的节点不是第一个节点
  67. previous.next = current.next;
  68. size--;
  69. }
  70. return true;
  71. }
  72. //判断链表是否为空
  73. public boolean isEmpty(){
  74. return (size == 0);
  75. }
  76. //显示节点信息
  77. public void display(){
  78. if(size > 0){
  79. Node node = head;
  80. int template = size;
  81. if(template == 1){
  82. System.out.println("[" + node.data + "]");
  83. return;
  84. }
  85. while(template > 0){
  86. if(node.equals(head)){
  87. System.out.print("["+node.data + "->");
  88. }else if(node.next == null){
  89. System.out.print(node.data + "]");
  90. }else{
  91. System.out.print(node.data + "]");
  92. }
  93. node = node.next;
  94. template--;
  95. }
  96. System.out.println();
  97. }else{//如果聊表一个节点都没有,直接打印【】
  98. System.out.println("[]");
  99. }
  100. }
  101. }

2、单向列表实现栈

栈中的pop()方法和push()方法,对应于链表的在头部删除元素deleteHead()以及在头部增加元素addHead()。


  
  1. public class StackSingleLink {
  2. private SingleLinkedList link;
  3. public StackSingleLink(){
  4. link = new SingleLinkedList();
  5. }
  6. //移除栈顶元素
  7. public Object pop(){//实现栈的pop()方法,返回的是栈移除的元素
  8. Object obj = link.delHead();
  9. return obj;
  10. }
  11. //添加元素
  12. public void push(Object obj){
  13. link.addHead(obj);
  14. }
  15. //判断栈中是否为空
  16. public boolean isEmpty(){
  17. return link.isEmpty();
  18. }
  19. //打印栈中的元素
  20. public void print(){
  21. link.display();
  22. }
  23. }

四、双向链表

对于单向链表,如果想在尾部添加一个节点,那么必须从头部一直遍历到尾部,找到尾部的节点,然后在尾节点后面插入一个节点,但是这样的操作很麻烦,但是如果我们在设计链表的时候加上一个对尾节点的引用,那么会简单的很多。

双向链表图

代码实现


  
  1. public class DoublePointLinkedList {
  2. private int size;//节点个数
  3. private Node head;//头节点
  4. private Node tail;//尾节点
  5. public class Node{
  6. private Object data;
  7. private Node next;
  8. public Node(Object obj){
  9. this.data = obj;
  10. }
  11. }
  12. public DoublePointLinkedList(){
  13. size = 0;
  14. head = null;
  15. tail = null;
  16. }
  17. //链表头部新增节点
  18. public void addHead(Object obj){
  19. Node node = new Node(obj);
  20. if(size == 0){ //判断链表是否为空
  21. head = node;
  22. tail = node;
  23. size++;
  24. }else{
  25. node.next = head;
  26. head = node;
  27. size++;
  28. }
  29. }
  30. //链表尾增加节点
  31. public void addTail(Object obj){
  32. Node node = new Node(obj);
  33. if(size == 0){
  34. head = node;
  35. tail = node;
  36. size++;
  37. }else{
  38. tail.next = node;
  39. tail = node;
  40. size++;
  41. }
  42. }
  43. //删除头部节点,成功返回true,失败返回false
  44. public boolean delHead(){
  45. if(size == 0){
  46. return false;
  47. }
  48. if(head.next == null){//表明链表中有一个节点
  49. head = null;
  50. tail = null;
  51. }else{
  52. head = head.next;
  53. }
  54. size--;
  55. return true;
  56. }
  57. //判断是否为空
  58. public boolean isEmpty(){
  59. return (size == 0);
  60. }
  61. //获得链表的节点个数
  62. public int getSize(){
  63. return size;
  64. }
  65. //显示节点信息
  66. public void display(){
  67. if(size > 0){
  68. Node node = head;
  69. int template = size;
  70. if(template > 0){
  71. if(node.equals(head)){
  72. System.out.print("[" + head.data + "->");
  73. }else if(node.next == null){
  74. System.out.print(tail.data + "]");
  75. }else{
  76. System.out.print( node.data + "->");
  77. }
  78. node = node.next;
  79. template--;
  80. }
  81. System.out.println();
  82. }else{//如果链表一个节点都没有,直接打印[]
  83. System.out.println("[]");
  84. }
  85. }
  86. }

队列(Queue)

队列可以用双端链表来实现。


  
  1. public class Queue {
  2. private DoublePointLinkedList list;
  3. private Queue(){
  4. list = new DoublePointLinkedList();
  5. }
  6. //向队列中插入一个对象(只能插入到尾部)
  7. public void insert(Object obj){
  8. list.addTail(obj);
  9. }
  10. //向队列中插入一个对象(只能从头部去除)
  11. public void remove(){
  12. list.delHead();
  13. }
  14. //判断队列中是否为空
  15. public boolean isEmpty(){
  16. return list.isEmpty();
  17. }
  18. //打印队列中的元素
  19. public void print(){
  20. list.display();
  21. }
  22. }

有序链表
前面的链表实现插入都是无序的,在有些应用中需要链表中的数据有序,这称之为有序链表。在有序链表中,数据是按照关键值有序排列的。一般在大多数需要使用有序数组的场合也可以使用有序链表。有序链表优于有序数组的地方是插入的速度(因为元素不需要移动),另外链表可以扩展到全部有效的使用内存,而数组只能局限于一个固定的大小中。
 


  
  1. public class OrderLinkedList {
  2. private Node head;
  3. public class Node{
  4. private int data;
  5. private Node next;
  6. public Node(int data){
  7. this.data = data;
  8. }
  9. }
  10. public OrderLinkedList(){
  11. head =null;
  12. }
  13. //插入节点,并且按照从小到大的顺序排列
  14. public void insert(int data){
  15. Node node = new Node(data);
  16. Node pre = null;
  17. Node current = head;
  18. while(current != null && current.data < node.data){
  19. pre = current;
  20. current = current.next;
  21. }
  22. if(pre == null){
  23. head = current;
  24. head.next = current;
  25. }else{
  26. pre.next = node;
  27. node.next = current;
  28. }
  29. }
  30. //删除节点
  31. public void delete(){
  32. head = head.next;
  33. }
  34. //打印节点
  35. public void display(){
  36. Node current = head;
  37. while(current != null){
  38. System.out.println(current.data + " ");
  39. current.next = current;
  40. }
  41. System.out.println("");
  42. }
  43. }

转载自:https://blog.csdn.net/enl0ve/article/details/80890225

文章来源: brucelong.blog.csdn.net,作者:Bruce小鬼,版权归原作者所有,如需转载,请联系作者。

原文链接:brucelong.blog.csdn.net/article/details/94589584

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。