标签:
链表是一种基本的一维离散存储数据结构。相对于数组,它是离散内存的,不能如数组一样通过下标来查询相应地数据,每一个链表节点只能知道它的上一个(双端链表)和它的下一个(单链表,双端链表)节点。C语言通过malloc/free控制内存,C++里通过new/delete,Java则是只有new对象。
1.Java链表节点定义
class Node{ private Node next; private int data; public Node(){ } public Node(int data){ this.data=data; } public int getData() { return data; } public void setData(int data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
2.链表操作类
class LinkedList{ private Node first; public Node getfirst() { return first; } public void setfirst(Node first) { this.first = first; } //按值搜寻第一个等于目标的节点 public Node findNode(int target){ if(first==null){ System.out.println("initialise the first"); return null; } Node p=first; while(p.getData()!=target && p!=null) p=p.getNext(); return p; } public Node findPreNode(Node target){ if(first==null){ System.out.println("initialise the first"); return null; } Node p=first; while(p.getNext()!=target) p=p.getNext(); return p; } //返回链表下标查找 public int IndexOfNode(int target){ int index=1; if(first==null){ System.out.println("initialise the first"); return -1; } Node p=first; while(p.getData()!=target) { index++; p=p.getNext(); if(p==null) { index=-1; break; } } return index; } //在末尾添加节点 public void addNode(Node add){ if(first==null){ first=add; add.setNext(null); return; } Node p=first; while(p.getNext()!=null) p=p.getNext(); p.setNext(add); add.setNext(null); } //头插法生成链表 public void headAdd(Node node){ if(first == null){ first=node; node.setNext(null); }else{ node.setNext(first); first=node; } } //删除节点--须指定链表中的节点 public void deleteNode(Node toDel){ if(first==null){ System.out.println("initialise the first"); return ; } Node p=toDel.getNext(); if(p!=null) { toDel.setNext(p.getNext()); toDel.setData(p.getData()); p.setNext(null); }else{ deleteEndNode(toDel); } } //删除末尾 public void deleteEndNode(Node toDel){ Node p=first; while(p.getNext()!=toDel && p!=null) p=p.getNext(); p.setNext(null); } //常规删除 public void deleteNormal(Node toDel){ Node p=findPreNode(toDel); p.setNext(toDel.getNext()); toDel.setNext(null); } //修改一个节点的值 public void update(Node target,int value){ if(first==null){ System.out.println("initialise the first"); return ; } target.setData(value); } public void printList(){ if(first==null){ System.out.println("initialise the first"); return ; } Node p=first; while(p!=null){ System.out.print(p.getData()+" "); p=p.getNext(); } System.out.println(); } }
小记:(1) 生成单链表可以有头插法和尾插法,尾插法的添加节点为O(n)复杂,删除也是O(n);头插法添加则是O(1),删除还是O(n)。
(2) 删除方法有一个是O(1)复杂度的。方法:给定一个节点,删除它下一个节点并把下一个节点的值转移到给定节点。
因为使用的是那个O(1)删除的方法,所以写得有些奇怪。总体方法就是使用一个O(n)空间来存储节点,发现重复就删除,遍历时间复杂就只用O(n)。
//删除未排序链表重复节点1 缓冲区版 public void DelRepeated1(LinkedList list){ HashMap<Integer,Boolean> buffer=new HashMap<Integer,Boolean>(); Node p=list.getfirst(); while(p!=null){ System.out.println("data="+p.getData()); if(buffer.get(p.getData())==null){ buffer.put(p.getData(), true); } else { list.deleteNode(p); while(true){ if(buffer.get(p.getData())!=null) list.deleteNode(p); else break; } } p=p.getNext(); } }
若不使用缓冲区,则只能使用暴力遍历法,从当前节点开始到表尾“排除异己”,“步步为营”。复杂度O(n*n)。
并且删除方法是使用O(n)复杂度的。
//删除未排序俩表重复节点2 无缓冲区 public void DelRepeated2(LinkedList list) { Node p = list.getfirst(); Node q = list.getfirst().getNext(); while(p!=null){ q = p.getNext(); while(q!=null){ if(p.getData()==q.getData()) list.deleteNormal(q); q=q.getNext(); } p = p.getNext(); } }
这个问题其实挺简单,如果链表是你自建的,那么添加个length或size属性记录那么解决这个问题就方便多了。如果仅给定一个单链表,则遍历一次找出length再以互补或互余的思维来求出倒k的下标。
//寻找倒数第k个节点 public Node findNK(LinkedList list,int k){ if(k<=0) { System.out.println("k should be upper than 0"); return null; } int n=0; Node p=list.getfirst(); while(p!=null) { n++; p=p.getNext(); } int result=n-k; if(n-k<0) { System.out.println("index out of range"); return null; } p=list.getfirst(); while(result!=0){ p=p.getNext(); result--; } return p; }
接到这道题的时候,我马上蹦出一个想法:排序。排完序就解决了。最快的排序算法也是O(n*logn)。然后想到快速排序,快速排序的partition函数可以一次将数组的分割成以基准元素为分界点的序列。这么一想,这道题可以做成O(n)复杂度了。实现它需要的数据结构为双端链表。
//双端链表分割 public void DivideLink(DoubleLink dl,int element){ DoubleNode tail=dl.getEnd().getPre(); DoubleNode first=dl.getFirst(); first.setData(element); int start=1; int end=dl.getLength(); int x=element; while(start<end){ while(start<end && tail.getData()>=x) { end--; tail=tail.getPre(); } if(start<end){ start++; first.setData(tail.getData()); first=first.getNext(); } while(start<end && first.getData()<=x) { start++; first=first.getNext(); } if(start<end){ tail.setData(first.getData()); end--; tail=tail.getPre(); } } first.setData(x); }
标签:
原文地址:http://www.cnblogs.com/chentingk/p/5723592.html