java linked list

Recently, a lot of linked list programs have been written in C language when training ACM. Because I was learning java recently, I wanted to write a linked list program in java, but I encountered a lot of difficulties. The following article summarizes the entire writing process very well and is worthy of collection.

       1. Creation and traversal of a singly linked list

  2. Find the number of nodes in a singly linked list

  3. Find the k-th node from the bottom in the singly linked list (the sword refers to the offer, question 15)

  4. Find the middle node in the singly linked list

  5. Merge two ordered singly linked lists, and the linked list after merging is still in order [high frequency of occurrence] (sword refers to offer, question 17)

  6. The inversion of the singly linked list [the highest frequency of occurrence] (the sword refers to the offer, question 16)

       7. Delete duplicate elements in a singly linked list

  8. Print a singly linked list from end to end (sword refers to offer, question 5)

  9. Determine whether a singly linked list has a cycle

  10. Take out the length of the ring in the linked list with rings

  11. In the singly linked list, take out the starting point of the ring (the sword refers to the offer, question 56). This question uses questions 8 and 9 above.

  12. Determine the first intersection of two singly linked lists (sword refers to offer, question 37)

1. Creation and traversal of a singly linked list:

public class LinkList{

	public Node head;

	public Node current;
	
	//Method: add data to the linked list
	public void add(int data){

		// when the linked list is determined to be empty
		if(head == null) {
			//If the head node is empty, it means that the linked list has not been created, then assign the new node to the head node

			head= new Node(data);

			current = head;
		}
		
		else{
			//Create a new node and place it behind the current node (associate the new node with the linked list)

			current.next = new Node(data);

			//Move the current index of the linked list one bit backward

			current = current.next; //After this step is completed, the current node points to the newly added node

		}

}

 

//Method: traverse the linked list (print out the linked list. The parameter of the method indicates that the traversal starts from the node node

	public void print(Node node) {

		if(node == null){
			
			return;
		
		}

 

		current = node;

		while(current != null) {

			System.out.println(current.data);	

			current = current.next;

		}

	}

 

	class Node {

		//Note: The permissions of the two member variables here cannot be private, because the permission of private is only accessible to this class.

		int data;//data field

		Node next;//Pointer field

 

		public Node(int data) {
		
			this.data = data;
		
		}
		
	}
		public static void main(String[] args) {
		
			LinkList list = new LinkList();//Add data to LinkList
		
				for(int i = 0; i < 10; i++) {
				
					list.add(i);
		        
				}
		                
		        list.print(list.head);//Start traversing the output from the head node
	
	}
	
}

In the above code, the Node node inside is represented by an inner class (line 60). The biggest advantage of using inner classes is that you can access each other privately with outer classes.

Note: The characteristics of inner class access are: the inner class can directly access the members of the outer class, including private ones; to access the members of the inner class, the outer class must first create an object.

In order to facilitate the operation of adding and traversing, a member variable current is added to the LinkList class to represent the index of the current node (line 05).

In the method of traversing the linked list (line 36), the parameter node indicates that the traversal starts from the node node, not necessarily from the head node.

 

2. Find the number of nodes in a singly linked list:

Be careful to check if the linked list is empty. The time complexity is O(n). This is relatively simple.

Core code:

//Method: Get the length of the singly linked list

	public int getLength(Node head) {

		if(head == null){
	
			return 0;
	
		}


		int length = 0;

		Node current = head;

		while(current != null){

			length++;

			current = current.next;

		}


		return length;

	}

3、查找单链表中的倒数第k个结点:

3.1  普通思路:

先将整个链表从头到尾遍历一次,计算出链表的长度size,得到链表的长度之后,就好办了,直接输出第(size-k)个节点就可以了(注意链表为空,k为0,k为1,k大于链表中节点个数时的情况

)。时间复杂度为O(n),大概思路如下:

	public int findLastNode(int index){ //index代表的是倒数第index的那个结点


		//第一次遍历,得到链表的长度size

		if(head == null){

			return-1;

		}

		int size=0;

		current = head;

		while(current!= null){

			size++;

			current = current.next;

		}



		//第二次遍历,输出倒数第index个结点的数据

		current = head;

		for(int i = 0;i < size - index; i++) {

			current = current.next;

		}



		return current.data;

	}

如果面试官不允许你遍历链表的长度,该怎么做呢?接下来就是。

 3.2  改进思路:(这种思路在其他题目中也有应用)

     这里需要声明两个指针:即两个结点型的变量first和second,首先让first和second都指向第一个结点,然后让second结点往后挪k-1个位置,此时first和second就间隔了k-1个位置,然后整体向后移动这两个节点,直到second节点走到最后一个结点的时候,此时first节点所指向的位置就是倒数第k个节点的位置。时间复杂度为O(n)

代码实现:(初版)

	public Node findLastNode(Node head, int index){

		if(head == null){

			return null;

		}

	 

		Node first = head;

		Node second = head;

		//让second结点往后挪index个位置

		for(int i= 0;i < index; i++) {

			second = second.next;

		}

	 

		//让first和second结点整体向后移动,直到second结点为Null

		while(second != null){

			first = first.next;

			second = second.next;

		}

	 

		//当second结点为空的时候,此时first指向的结点就是我们要找的结点

		return first;

	}

代码实现:(最终版)(考虑k大于链表中结点个数时的情况时,抛出异常)

上面的代码中,看似已经实现了功能,其实还不够健壮:

  要注意k等于0的情况;

  如果k大于链表中节点个数时,就会报空指针异常,所以这里需要做一下判断。

核心代码如下:

	public Node findLastNode(Node head, int k){  
		  
	    if(k == 0|| head == null) {  
	  
	        return null;  
	  
	    }  
	  
	  
	  
	    Node first = head;  
	  
	    Node second = head;  
	  
	  
	  
	    //让second结点往后挪k-1个位置  
	  
	    for(int i = 0; i < k - 1; i++) {  
	  
	        System.out.println("i的值是"+ i);  
	  
	        second = second.next;  
	  
	        if(second == null) { //说明k的值已经大于链表的长度了  
	  
	            //throw  
	            new NullPointerException("链表的长度小于" + k); //我们自己抛出异常,给用户以提示  
	  
	            return null;  
	  
	        }  
	  
	    }  
	    
	    //让first结点向后挪k-1个位置
	    for(int i=0; i < k-1;i++) {
	    	
	    	first=first.next;
	    
	    }
	    
	    return first;//返回此时first的值即为要找点的值

	}

4、查找单链表中的中间结点:

同样,面试官不允许你算出链表的长度,该怎么做呢?

思路:

    和上面的第2节一样,也是设置两个指针first和second,只不过这里是,两个指针同时向前走,second指针每次走两步,first指针每次走一步,直到second指针走到最后一个结点时,此时first指针所指的结点就是中间结点。注意链表为空,链表结点个数为1和2的情况。时间复杂度为O(n)。

代码实现:

	//方法:查找链表的中间结点

	public Node findMidNode(Node head) {
	 

		if(head == null) {

			return null;

		}

		Node first = head;

		Node second = head;

		//每次移动时,让second结点移动两位,first结点移动一位

		while(second != null&& second.next != null) {

			first = first.next;

			second = second.next.next;

		}

		//直到second结点移动到null时,此时first指针指向的位置就是中间结点的位置

		return first;

	}

上方代码中,当n为偶数时,得到的中间结点是第n/2 + 1个结点。比如链表有6个节点时,得到的是第4个节点。

 

5、合并两个有序的单链表,合并之后的链表依然有序:

    这道题经常被各公司考察。

例如:

链表1:

  1->2->3->4

链表2:

  2->3->4->5

合并后:

  1->2->2->3->3->4->4->5

解题思路:

  挨着比较链表1和链表2。

  这个类似于归并排序。尤其要注意两个链表都为空、和其中一个为空的情况。只需要O (1) 的空间。时间复杂度为O (max(len1,len2))

代码实现:

//两个参数代表的是两个链表的头结点

	public Node mergeLinkList(Node head1, Node head2) {
	 
		if(head1 == null&& head2 == null) { //如果两个链表都为空

			return null;

		}

		if(head1 == null) {

			return head2;

		}

		if(head2 == null) {

			return head1;

		}

	 

		Node head; //新链表的头结点

		Node current; //current结点指向新链表

		// 一开始,我们让current结点指向head1和head2中较小的数据,得到head结点

		if(head1.data < head2.data) {

			head = head1;

			current = head1;

			head1 = head1.next;

		}
		
		else{

			head = head2;

			current = head2;

			head2 = head2.next;

		}

	 

		while(head1 != null && head2 != null) {

			if(head1.data < head2.data) {

				current.next = head1; //In the new linked list, the next node of the current pointer corresponds to the smaller data

				current = current.next; //current pointer moves down

				head1 = head1.next;

			}
			
			else{

				current.next = head2;

				current = current.next;

				head2 = head2.next;

			}

		}

	 

	 // merge the remaining elements

		if(head1 != null) { //Indicates that the linked list 2 has been traversed and is empty

			current.next = head1;

		}

	 

		if(head2 != null) { //Indicates that the linked list 1 has been traversed and is empty

			current.next = head2;

		}

	 

		return head;

	}
 

Code test:
public static void main(String[] args) {

		LinkList list1 = newLinkList();

		LinkList list2 = newLinkList();

		//Add data to LinkList

		for(int i = 0; i < 4; i++) {

			list1.add(i);

		}

			 

		for(int i = 3; i < 8; i++) {

			list2.add(i);

		}

			 
		LinkList list3 = newLinkList();

		list3.head = list3.mergeLinkList(list1.head, list2.head); //Merge list1 and list2 and store them in list3

		list3.print(list3.head);// Traverse the output from the head node

	}

The add method and print method used in the above code are the same as those in Section 1.


6. Inversion of a singly linked list:

	 public static Node reverse(Node head)  
	    {  
	        if (null == head)  
	        {  
	           return null; 
	        }  
	        Node pre = head;  
	        Node cur = head.next;  
	        Node next;  
	        while (null != cur)  
	        {  
	            next = cur.next;  
	            cur.next=pre;  
	            pre = cur;  
	            cur = next;  
	        }  
	  
	        // 将原链表的头节点的下一个节点置为null,再将反转后的头节点赋给head  
	        head.next=null;  
	        return pre;
	    }  

}

7、删除单链表中的重复元素:

	public static int deleteDupsNew(Node head) {  
	    if (head == null) return 0;  
	    Node current = head;
	    int x=0;
	    while(current != null){  
	        Node runner = current;  
	        while (runner.next != null){  
	            if(runner.next.data == current.data){  
	                runner.next = runner.next.next;
	                x++;
	            }  
	            else{  
	                runner = runner.next;  
	            }  
	        }  
	        current = current.next;  
	    }
	    return x;
	}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325701040&siteId=291194637