重温数据结构:单链表的常见问题总结

1.单链表的常见问题:
 *  求单链表中结点的个数: getListLength 
 *  将单链表反转: reverseList(遍历),reverseListRec(递归) 
 *  查找单链表中的倒数第K个结点(k > 0): reGetKthNode 
 *  查找单链表的中间结点: getMiddleNode (快慢指针)
 *  从尾到头打印单链表: reversePrintListStack,reversePrintListRec(递归) 
 *  已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序: mergeSortedList, mergeSortedListRec 
 *  判断一个单链表中是否有环: hasCycle 
 *  判断两个单链表是否相交: isIntersect 
 *  求两个单链表相交的第一个节点: getFirstCommonNode 
 *  已知一个单链表中存在环,求进入环中的第一个节点: getFirstNodeInCycle, getFirstNodeInCycleHashMap 
 *  给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted: delete 
 参考:http://blog.csdn.net/fightforyourdream/article/details/16353519

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

/*
 *@author: ZhengHaibo  
 *web:     http://blog.csdn.net/nuptboyzhb
 *mail:    [email protected]
 *2014-3-10  Nanjing,njupt,China
 */
/**
 * 单链表
 */
public class MySingleLinkedList {
	/**
	 * 定义节点的数据结构
	 */
	public class Node {
		public Node next;//存储下一个节点的地址
		public int data;//数据区
	}
	/**
	 * 插入节点
	 * @param head 链表的头
	 * @param data 要插入的节点数据
	 * @param i 插入的位置
	 */
	public boolean insert(Node head,int data,int i){
		Node p = head;
		int j = 0;
		while(p!=null&&ji-1){//i大于表长度+1 或者 i<1
			System.out.println("ERROR");
			return false;
		}
		Node node = new Node();
		node.data = data;
		node.next = p.next;
		p.next = node;
		return true;
	}
	/**
	 * 删除第i个元素,并且将删除后的元素保存在data中
	 * @param head 链表的头
	 * @param i 删除元素的位置
	 * @param data 删除元素的数据区
	 * @return
	 */
	public boolean remove(Node head,int i,int data){
		Node p = head;
		int j = 0;
		while(p.next!=null&&ji-1){//删除的位置不合理
			return false;
		}
		data = p.next.data;//将要删除的点的数据保存到data中
		p.next = p.next.next;//删除p.next
		return true;
	}
	/**
	 * 合并2个有序链表(非递减)
	 * @param head1 待合并的有序链表1
	 * @param head2 待合并的有序链表2
	 * @param head 合并后的有序链表
	 */
	public void mergeList(Node head1,Node head2,Node head){
		 Node pa = head1.next;
		 Node pb = head2.next;
		 Node pc = head;
		 while(pa!=null&&pb!=null){
			 if(pa.data stack=new Stack();
		Node pNode=head;
		while (pNode.next!=null) {//入栈
			pNode=pNode.next;
			stack.push(pNode);
		}
		Node pp=head;
		while(!stack.isEmpty()){//出栈
			Node node=stack.pop();
			pp.next=node;
			pp=node;
		}
		pp.next=null;//防止出现循环链表
	}
	/**
	 * 获取链表的长度
	 * @param head
	 * @return
	 */
	public int getListLen(Node head){
		Node p=head;
		int len=0;
		while(p.next!=null){
			p=p.next;
			len++;
		}
		return len;
	}
	/**
	 * 获取链表中的倒数第K个节点
	 * 思路1:先获取链表的长度n,然后求取第n+1-k个元素
	 * @param head
	 * @param k 
	 * @return
	 */
	public Node reGetKthNode1(Node head,int k){
		int len=0;
		Node p=head;
		while(p.next!=null){//计算链表长度
			len++;
			p=p.next;
		}
		if(k<1||k>len){
			return null;
		}
		Node ppNode=head;
		int index=0;
		while(ppNode.next!=null){
			ppNode=ppNode.next;
			index++;
			if(index==len+1-k){
				return ppNode;
			}
		}
		return null;
	}
	/**
	 * 获取链表中的倒数第K个节点
	 * 思路2:定义2个指针p1和p2,先让p2移动k-1步
	 * 然后再p1和p2一起移动,直到p2.next==null的时候,
	 * p1即为倒数第K个元素
	 * @param head
	 * @param k
	 * @return
	 */
	public Node reGetKthNode2(Node head,int k){
		Node p1=head,p2=head;
		int step=0;
		while(p2.next!=null&&step map=new HashMap();
		while(p.next!=null){
			p=p.next;
			if(map.get(p)==null){//如果map中还没有这个节点,将其put进入
				map.put(p, "1");
			}else {
				return p;
			}
		}
		return null;
	}
	/**
	 * 在两个链表中制作一个相交点
	 * 在head2的倒数第二个节点制作一个相交点
	 * @param head1
	 * @param head2
	 */
	public void makeCrossingNode(Node head1,Node head2){
		Node p1=head1;
		Node p2=head2;
		while(p1.next!=null){
			p1=p1.next;
		}
		while(p2.next.next!=null){
			p2=p2.next;
		}
		p1.next=p2;
	}
	/**
	 * 判断2个链表是否相交
	 * 思路:遍历两个链表,看最后一个节点是否相同
	 * @param head1
	 * @param head2
	 * @return
	 */
	public boolean isListCrossing(Node head1,Node head2){
		Node p1=head1;
		Node p2=head2;
		while(p1.next!=null){
			p1=p1.next;
		}
		while(p2.next!=null){
			p2=p2.next;
		}
		return p1==p2;
	}
	/**
	 * 获取两条相交链表的第一个公共节点
	 * 思路1:HashMap 缺点:增加了空间复杂度
	 * 思路2:
	 * 对第一个链表遍历,计算长度len1,同时保存最后一个节点的地址。 
     * 对第二个链表遍历,计算长度len2,同时检查最后一个节点是否和
     * 第一个链表的最后一个节点相同,若不相同,不相交,结束。 
     * 两个链表均从头节点开始,假设len1大于len2 
     * ,那么将第一个链表先遍历len1-len2个节点,此时两个链表当前
     * 节点到第一个相交节点的距离就相等了,然后一起向后遍历,直到
     * 两个节点的地址相同。 
     * 时间复杂度,O(len1+len2) 
	 * @param head1
	 * @param head2
	 * @return
	 */
	public Node getFristCrossingNode(Node head1,Node head2){
		Node p1=head1;
		Node p2=head2;
		int len1=0,len2=0;
		while(p1.next!=null){
			len1++;
			p1=p1.next;
		}
		while(p2.next!=null){
			len2++;
			p2=p2.next;
		}
		if(p2!=p1){//说明不相交
			return null;
		}
		Node pp1=head1;
		Node pp2=head2;
		int step;//计算长的链表比短的链表长了多少
		if(len1>=len2){
			step=len1-len2;
			for(int i=0;i


~使用归并排序算法,对单链表进行排序
/*
 * $filename: SortLinkedList.java,v $
 * $Date: 2014-9-7  $
 * Copyright (C) ZhengHaibo, Inc. All rights reserved.
 * This software is Made by Zhenghaibo.
 */
package edu.njupt.zhb;
/*
 *@author: ZhengHaibo  
 *blog:     http://blog.csdn.net/nuptboyzhb
 *mail:    [email protected]
 *web:     http://www.mobctrl.net
 *2014-9-7  Nanjing,njupt,China
 */
public class SortLinkedList {
	public class ListNode {
		public int val;
		public ListNode next;
	 
		public ListNode(int x) {
			val = x;
			next = null;
		}
	}
	// merge sort
	public ListNode mergeSortList(ListNode head) {
 
		if (head == null || head.next == null)
			return head;
 
		// count total number of elements
		int count = 0;
		ListNode p = head;
		while (p != null) {
			count++;
			p = p.next;
		}
 
		// break up to two list
		int middle = count / 2;
 
		ListNode l = head, r = null;
		ListNode p2 = head;
		int countHalf = 0;
		while (p2 != null) {
			countHalf++;
			ListNode next = p2.next;
 
			if (countHalf == middle) {
				p2.next = null;
				r = next;
			}
			p2 = next;
		}
 
		// now we have two parts l and r, recursively sort them
		ListNode h1 = mergeSortList(l);
		ListNode h2 = mergeSortList(r);
 
		// merge together
		ListNode merged = merge(h1, h2);
 
		return merged;
	}
 
	public  ListNode merge(ListNode l, ListNode r) {
		ListNode p1 = l;
		ListNode p2 = r;
 
		ListNode fakeHead = new ListNode(100);
		ListNode pNew = fakeHead;
 
		while (p1 != null || p2 != null) {
 
			if (p1 == null) {
				pNew.next = new ListNode(p2.val);
				p2 = p2.next;
				pNew = pNew.next;
			} else if (p2 == null) {
				pNew.next = new ListNode(p1.val);
				p1 = p1.next;
				pNew = pNew.next;
			} else {
				if (p1.val < p2.val) {
					// if(fakeHead)
					pNew.next = new ListNode(p1.val);
					p1 = p1.next;
					pNew = pNew.next;
				} else if (p1.val == p2.val) {
					pNew.next = new ListNode(p1.val);
					pNew.next.next = new ListNode(p1.val);
					pNew = pNew.next.next;
					p1 = p1.next;
					p2 = p2.next;
 
				} else {
					pNew.next = new ListNode(p2.val);
					p2 = p2.next;
					pNew = pNew.next;
				}
			}
		}
		return fakeHead.next;
	}
	
	public void test(){
		ListNode n1 = new ListNode(2);
		ListNode n2 = new ListNode(8);
		ListNode n3 = new ListNode(4);
 
		ListNode n4 = new ListNode(5);
		ListNode n5 = new ListNode(4);
		ListNode n6 = new ListNode(9);
 
		n1.next = n2;
		n2.next = n3;
		n3.next = n4;
		n4.next = n5;
		n5.next = n6;
 
		n1 = mergeSortList(n1);
 
		printList(n1);
	}
	
	public static void main(String[] args) {
		new SortLinkedList().test();
	}
 
	public void printList(ListNode x) {
		if(x != null){
			System.out.print(x.val + " ");
			while (x.next != null) {
				System.out.print(x.next.val + " ");
				x = x.next;
			}
			System.out.println();
		}
 
	}
}


2.附录:
重温数据结构:单链表的常见问题总结_第1张图片
重温数据结构:单链表的常见问题总结_第2张图片
重温数据结构:单链表的常见问题总结_第3张图片
重温数据结构:单链表的常见问题总结_第4张图片
图3-9在单链表中删除节点

你可能感兴趣的:(【算法】)