码迷,mamicode.com
首页 > 其他好文 > 详细

链表问题总结

时间:2016-07-31 19:17:34      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

  • 链表

  链表是一种基本的一维离散存储数据结构。相对于数组,它是离散内存的,不能如数组一样通过下标来查询相应地数据,每一个链表节点只能知道它的上一个(双端链表)和它的下一个(单链表,双端链表)节点。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)复杂度的。方法:给定一个节点,删除它下一个节点并把下一个节点的值转移到给定节点。

  • 问题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();

		}
		
	}
  • 问题2:寻找倒数低k个节点。

    这个问题其实挺简单,如果链表是你自建的,那么添加个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;
	}
  • 问题3:给定一个值x,将链表分割成两部分,大于x部分和小与x部分。

    接到这道题的时候,我马上蹦出一个想法:排序。排完序就解决了。最快的排序算法也是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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!