Before deep explore the algorithm related to linkedlist, I firstly review the basic operation towards a linkedlist as follows.
package com.way.collection.list.linkedlist;
public class Node {
public Node next=null;
public int data;
public Node(int data){
this.data=data;
}
public Node addtotail(int data){
Node end=new Node(data);
Node node=this;
while(node.next!=null){
node=node.next;
}
node.next=end;
return this;
}
public Node addAfter(int data,int index){
Node add=new Node(data);
Node node=this;
while(node!=null){
if(node.data==index){
add.next=node.next;
node.next=add;
return this;
}
}
return this;
}
public Node deleteFirst(int data){
Node node=this;
if(node.data==data){
return this.next;
}
while(node!=null){
if(node.next.data==data){
node.next=node.next.next;
return this;
}
}
return this;
}
public void traverse(){
Node node=this;
while(node!=null){
System.out.println(node.data);
node=node.next;
}
}
public static void main(String[] args){
Node node=new Node(1);
node.addtotail(2);
node.addtotail(3);
node.addtotail(4);
node.traverse();
node=node.deleteFirst(2);
node.traverse();
node.addAfter(0, 1);
node.traverse();
node=node.deleteFirst(1);
node.traverse();
}
}
After practicing some algorithm question, I found some tips.
Tips:
1, Be careful about the head address of linkedlist
For any operation that may delete the head node of the linkedlist. We should use the method like this: node=node.deleteFirst(1);
Because the reference address will be changed when deleting the head. So I have to refresh the “node” like this. Otherwise it will lead to fault when we delete the head node.
That is also why it is a good habit to define a new object in a linkedlist related function, as Node head=this; Node node=head;
“head” is preserved particularly for the first node in linkedlist, while “node” is the pointer for operation.
2,Recursion
Algorithm about linkedlist always use recursions. The complexity will increase rapidly. For example:
Write code to remove duplicates from an unsorted linked list. How would you solve this problem if a temporay buffer is not allowed.
Write code to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x.
Here is the code for above questions:
Remove Duplication:
public Node removeDuplicate(){
Node head=this;
Node node=head;
/*如果是单节点,直接返回*/
if(node.next==null){
return node;
}
/*不是单节点,继续进行*/
//记录头结点数据
int data=head.data;
//当节点有后续节点时,向后移动
while(node.next!=null){
node=node.next;
//如果节点数据等于头结点数据,抛弃头节点,即对第头节点之后的链表,进行查重,递归调用
if(data==node.data){
return head.next.removeDuplicate();
}
}
//如果没有与头节点数据重复的节点,检查后续的节点,但头节点保留
head.next=head.next.removeDuplicate();
//返回头节点
return head;
}
Partition:
In solving this question, I have made a serious mistake.
My original solution is this:
public Node partition(int index){
Node head=this;
if(head.next==null){
return head;
}
if(head.data>=index){
head=head.addtotail(head.data);
head=head.next.partition(index);
}else{
head.next=head.next.partition(index);
}
return head;
}
I debug it for hours until I realize I made a endless loop. I put each data greater than or equal to x to the tail of the list. Indeed it can partition the linked list but the program will keep rotating the nodes at the list tail. (e.g. Input: 1,5,4,2,3),x=3, the algorithm can get “1,2,3,5,4” after several loop but the “4” and “5” will be swapped again and again, never stop. )
It is possible to define a integer to store the length of the list, and force to quick the circle after limited number of loops. But the algorithm seems ugly. And i cost a lot of memory in JVM stack as it has too many recursions.
The ideal method is like this:
public Node partition(int index){
Node less=null;
Node more=null;
Node node=this;
while(node.next!=null){
if(node.data>=index){
if(more==null){//判断是否为空,如果为空初始化头节点,如果不为空,向尾部加入
more=new Node(node.data);
}else{
more.addtotail(node.data);
}
}else{
if(less==null){
less=new Node(node.data);
}else{
less.addtotail(node.data);
}
}
node=node.next;
}
return less.addtotail(more);
}
3, Singly Linked List and Doubly Linked List
In singly linked list, when we want to change the location of a node. We have to do like this:
public Node deleteFirst(int data){
Node node=this;
if(node.data==data){
return this.next;
}
while(node!=null){
if(node.next.data==data){
node.next=node.next.next;
return this;
}
}
return this;
}
node.next=mode.next.next;
It seems like a ridiculous code but I have to do so. Because I can’t get the previous node according to current node. There is no this problem in doubly linked list.
class DoublyLinkedListNode{
int data;
DoublyLinkedListNode previous=null;
DoublyLinkedListNode next=null;
}
As a result, doubly linked list consume more space but it benefit for algorithm which needs many location change, such as sort algorithms.
To be continue……