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("\n**************************");  
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         }  

 

  

    

 

posted @ 2017-09-04 18:01  白日梦想家12138  阅读(376)  评论(0编辑  收藏  举报