标签:
链表是一种基本的一维离散存储数据结构。相对于数组,它是离散内存的,不能如数组一样通过下标来查询相应地数据,每一个链表节点只能知道它的上一个(双端链表)和它的下一个(单链表,双端链表)节点。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