zoukankan      html  css  js  c++  java
  • Java实现单向链表

    Java实现链表的思想可以参考 LinkedList的源码

    下面实现几点关于单向链表的一些操作:

      1 public class LinkList<E> {
      2     private Node<E> first;
      3     private Node<E> last;
      4     private int  size;
      5     
      6     public LinkList() {
      7         first = last = null;
      8         size = 0;    
      9     }
     10     
     11     
     12     private static class Node<E> {
     13         private Node<E> next;
     14         private E data;
     15         public Node(E data,Node<E> next) {    
     16             this.data = data;
     17             this.next = next;        
     18         }
     19     }
     20     
     21     public void add(E e) {
     22         Node<E> l = last;
     23         Node<E> newNode = new Node<E>(e, null);
     24         last = newNode;
     25         if(first == null) {
     26             first = newNode;
     27         } else {
     28             l.next = newNode;
     29         }
     30         size++;
     31     }
     32     
     33 
     34     
     35     public static void main(String[] args) {
     36         LinkList<Integer> link = new LinkList<Integer>();
     37         //1.添加
     38         link.add(1);
     39         link.add(2); 
     40         link.add(3);
     41         link.add(4);
     42         
     43         System.out.println("节点个数:" + link.size);
     44         
     45         //2.遍历
     46         Node<Integer> node1 = link.first;
     47         for(int i = 0;i<link.size;i++) {
     48             if(link.first != null) {
     49                 System.out.println(node1.data);
     50                 node1 = node1.next;
     51             }
     52         }
     53         
     54         //3.查找单链表中的倒数第k个结点
     55         int k = 2;
     56         //倒数第k个,就是正数第link.size-k+1,(因为是单向,只能正着数)
     57         int index = link.size-k+1;
     58         Node<Integer> node2 = link.first;
     59         
     60         if(link.size <= 0) {
     61             System.out.println("链表为空");
     62             return;
     63         }
     64         if(link.size <= k && link.size > 0) {
     65             System.out.println(node2.data); 
     66             return;
     67         }
     68         
     69         for(int i = 1;i<index;i++) {    
     70             node2 = node2.next;
     71         }
     72         
     73         System.out.println("这个链表中倒数第" + k + "个节点的值为:" + node2.data);
     74         
     75         //4.查找单链表中的中间节点(size + 1 / 2,然后遍历吧)
     76         
     77         //5.合并两个有序的单链表,合并之后,仍然有序;
     78         //这里自己的思路是,创建一个新的链表,将这两个有序的链表中的数据,按序放入到 新链表中
     79         LinkList<Integer> link2 = new LinkList<Integer>();
     80         LinkList<Integer> link3 = new LinkList<Integer>();
     81         link2.add(0);
     82         link2.add(2); 
     83         link2.add(3); 
     84         link2.add(2);
     85         link2.add(7);
     86         link2.add(7);
     87         
     88         Node<Integer> node3 = link.first;
     89         Node<Integer> node4 = link2.first;
     90         
     91         //只有链表1和链表2中还有数据可以放入新链表
     92         for(;node3 != null || node4 != null;) {
     93             
     94             //当链表1和链表2中都有数据可以去比较,
     95             if(node3 != null && node4 != null) {
     96                 if(node3.data < node4.data) {
     97                     link3.add(node3.data);
     98                     node3 = node3.next;
     99                 }
    100                 else if(node3.data > node4.data) {
    101                     link3.add(node4.data);
    102                     node4 = node4.next;
    103                 } else if(node3.data == node4.data) {
    104                     link3.add(node3.data);
    105                     link3.add(node4.data);
    106                     node3 = node3.next;
    107                     node4 = node4.next;
    108                 }
    109             }
    110             
    111             
    112             //若链表1的数据已经比较完了,链表2的还有数据存在,说明链表2这些剩下的数据都比链表1里面大,直接全部放到新链表后面
    113             if(node3 == null && node4 != null) {
    114                 link3.add(node4.data);
    115                 node4 = node4.next;
    116             } else if(node3 != null && node4 == null) {
    117                 link3.add(node3.data);
    118                 node3 = node3.next;
    119             }    
    120             
    121         }
    122         System.out.print("两个有序的单链表合并后:");
    123         for(int i = 0;i<link3.size;i++) {
    124             System.out.print(link3.first.data + " ");
    125             link3.first = link3.first.next;
    126         }
    127         System.out.println("");
    128         System.out.println("------------------华丽丽的分割线--------------------");
    129         
    130         //6.单链表的反转
    131         Node<Integer> node5 = link.first;
    132 
    133         Node<Integer> pre = null;
    134         Node<Integer> next = null;
    135         
    136         while(node5 != null) {
    137             next = node5.next;
    138             node5.next = pre;
    139             pre = node5;
    140             node5 = next;
    141             
    142         }
    143         
    144         while(pre != null) {
    145             System.out.print(pre.data + " ");
    146             pre = pre.next;
    147         }
    148     }
    149 }

    注:上面的代码写得比较糟糕,也有很多可以封装的地方,等有时间再整理

    提比较重要的几点:

      1.关于链表中的泛型,用到泛型的地方,

        a)创建这个LinkList的时候,

        b)创建Node节点的时候,

        c)往Node中添加的数据

      2.关于单向链表的添加,

        a)添加就是添加在链表的末尾,添加之前,肯定要创建一个 Node节点出来,这个Node节点的下一个节点为null

        b)先保存原来的last节点,将这个newNode作为新的last节点

        c)如果原先列表中不存在节点,则这个newNode就为 first节点

        d)将原来的last节点的next指向这个newNode,就完成添加了 ,最后size++

      3.关于合并两个有序的单链表,

        a)这里自己的思路是,创建一个新的链表,将这两个有序的链表中的数据,按序放入到 新链表中,当然还有别的思路

      4.关于单向链表的反转,

        a)首先要有一个pre节点和 next 节点,用于保存当前节点的前一个节点和后一个节点

        b)

          用前面定义的next,保存当前节点的下一个节点

          当前节点下一节点重新指向当前节点的前一节点(箭头反向) 1->2->3    1<-2  3   这里体现上一句的必要性了,如果没有保存,那么后面就找不到这个 3 了

          让pre,当前节点,next,依次向后移动,这样就可以对下一个节点进行反转

        c)还有一种递归的方式,递归和直接遍历的区别就是,直接遍历是从前往后按顺序一个一个反转

          递归是从后往前,先反转最后一个节点,再回头反转前面

      这边给出一个递归的示例:

     1  public static void main(String[] args) {  
     2         Node head = new Node(0);  
     3         Node node1 = new Node(1);  
     4         Node node2 = new Node(2);  
     5         Node node3 = new Node(3);  
     6         head.setNext(node1);  
     7         node1.setNext(node2);  
     8         node2.setNext(node3);  
     9   
    10         // 打印反转前的链表  
    11         Node h = head;  
    12         while (null != h) {  
    13             System.out.print(h.getData() + " ");  
    14             h = h.getNext();  
    15         }  
    16         // 调用反转方法  
    17         head = Reverse1(head);  
    18   
    19         System.out.println("
    **************************");  
    20         // 打印反转后的结果  
    21         while (null != head) {  
    22             System.out.print(head.getData() + " ");  
    23             head = head.getNext();  
    24         }  
    25     }  
    26   
    27     /** 
    28      * 递归,在反转当前节点之前先反转后续节点 
    29      */  
    30     public static Node Reverse1(Node head) {  
    31         // head看作是前一结点,head.getNext()是当前结点,reHead是反转后新链表的头结点  
    32         if (head == null || head.getNext() == null) {  
    33             return head;// 若为空链或者当前结点在尾结点,则直接还回  
    34         }  
    35         Node reHead = Reverse1(head.getNext());// 先反转后续节点head.getNext()  
    36         head.getNext().setNext(head);// 将当前结点的指针域指向前一结点  
    37         head.setNext(null);// 前一结点的指针域令为null;  
    38         return reHead;// 反转后新链表的头结点  
    39     }  
    40 }  
    41   
    42     class Node {  
    43         private int Data;// 数据域  
    44         private Node Next;// 指针域  
    45   
    46         public Node(int Data) {  
    47             // super();  
    48             this.Data = Data;  
    49         }  
    50   
    51         public int getData() {  
    52             return Data;  
    53         }  
    54   
    55         public void setData(int Data) {  
    56             this.Data = Data;  
    57         }  
    58   
    59         public Node getNext() {  
    60             return Next;  
    61         }  
    62   
    63         public void setNext(Node Next) {  
    64             this.Next = Next;  
    65         }  

      

        

  • 相关阅读:
    C# extern关键字的用法
    C#自定义集合类(二)
    C#自定义集合类(一)
    LINQ中交集、并集、差集、去重(十四)
    LINQ中转换操作符(十三)
    Oracle实现连乘和求和
    适配器模式
    HTTP网络协议与手写Web服务容器
    代理模式
    设计模式的几条家规
  • 原文地址:https://www.cnblogs.com/xuzekun/p/7474805.html
Copyright © 2011-2022 走看看