链表面试题总结(java实现)

 关于链表的基本实现在上另一篇博客里面有写http://blog.csdn.net/a447332241/article/details/78947827

这里简单总结一下一些常见的链表面试题

1.链表反转

2.为尾到头打印链表

3.合并有序链表

4.判断链表是否有环

5.求链表的倒数第k个结点


1.链表反转

我们定义三个指针,分别记录当前遍历到的结点,它的前一个结点以及后一个结点,然后依次遍历,将当前结点的指针指向上一个结点。

  public static Node  reverse(Node head)
    {
    	if(head==null||head.next==null)
    		return head;
    	
    	Node cur = head.next;  //当前反转结点结点  
    	Node pre = head;		//前一个结点
    	Node tmp=null;			//中间结点 保存当前结点的下一个结点位置
    	while(cur!=null)
    	{
    		tmp=cur.next; //保存下一个结点
    		
    		cur.next=pre; //反转指向
    		
    		//向后遍历
    		pre=cur;      
    		cur=tmp;											
    	}
    	
    	head.next=null;
    	
    	return pre;
    }

2.从尾到头打印链表

对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。所以,这一题要么自己使用栈,要让系统使用栈,也就是递归。注意链表为空的情况。时间复杂度为O(n)

  注:不要想着先将单链表反转,然后遍历输出,这样会破坏链表的结构,不建议。


自己新建一个栈
//方法:从尾到头打印单链表
	     public static void reversePrint(Node head) {
	 
	         if (head == null) {
	             return;
	          }
	  
	         Stack<Node> stack = new Stack<Node>();  //新建一个栈
	          Node current = head;
	 
	        //将链表的所有结点压栈
	         while (current != null) {
	             stack.push(current);  //将当前结点压栈
	             current = current.next;
	         }
	
	         //将栈中的结点打印输出即可
	        while (stack.size() > 0) {
	             System.out.println(stack.pop().data);  //出栈操作
	         }
	     }
  使用系统的栈,递归实现

    //使用系统的栈
	     public static  void reversePrint1(Node head) {
    	 
 
         if (head == null) {
             return;
         }
         reversePrint(head.next);
         System.out.println(head.data);
     }

3.合并有序链表

这里提供两种方法1.类似于归并排序。尤其要注意两个链表都为空、和其中一个为空的情况。只需要O (1) 的空间。时间复杂度为O (max(len1,len2))

	// 两个参数代表的是两个链表的头结点
	public Node mergeLinkList(Node head1, Node head2) {

		if (head1 == null && head2 == null) { // 如果两个链表都为空
			return null;
		}
		if (head1 == null) {
			return head2;
		}
		if (head2 == null) {
			return head1;
		}

		Node head; // 新链表的头结点
		Node current; // current结点指向新链表

		// 一开始,我们让current结点指向head1和head2中较小的数据,得到head结点
		if (head1.data < head2.data) {
			head = head1;
			current = head1;
			head1 = head1.next;
		} else {
			head = head2;
			current = head2;
			head2 = head2.next;
		}

		while (head1 != null && head2 != null) {
			if (head1.data < head2.data) {
				current.next = head1; // 新链表中,current指针的下一个结点对应较小的那个数据
				current = current.next; // current指针下移
				head1 = head1.next;
			} else {
				current.next = head2;
				current = current.next;
				head2 = head2.next;
			}
		}

		// 合并剩余的元素
		if (head1 != null) { // 说明链表2遍历完了,是空的
			current.next = head1;
		}

		if (head2 != null) { // 说明链表1遍历完了,是空的
			current.next = head2;
		}

		return head;
	}
2.利用递归实现
	// 两个参数代表的是两个链表的头结点
	public static Node merage(Node head1, Node head2) {
		if (head1 == null)
			return head2;
		if (head2 == null)
			return head1;

		Node head3 = null;

		if (head1.data < head2.data) {
			head3 = head1;
			head3.next = merage(head1.next, head2);
		} else {
			head3 = head2;
			head3.next = merage(head1, head2.next);
		}
		return head3;//返回合并后链表的头结点

	}
4.判断链表是否有环

思路:定义两个指针,我们用两个指针去遍历:first指针每次走一步,second指针每次走两步,如果first指针和second指针相遇,说明有环。

// 判断单链表是否有环,我们用两个指针去遍历:
	// first指针每次走一步,second指针每次走两步,如果first指针和second指针相遇,说明有环。
	public static boolean hasCycle(Node head) {

		if (head == null) {
			return false;
		}

		Node first = head;
		Node second = head;

		while (second != null) {
			first = first.next; // first指针走一步
			second = second.next.next; // second指针走两步

			if (first == second) { // 一旦两个指针相遇,说明链表是有环的
				return true;
			}
		}

		return false;
	}

5.求链表的倒数第k个结点

常规思路:假设整个链表有n个结点,那么倒数第k个结点就是从头结点开始的第n-k+1个结点,所以我们可以遍历链表两次,第一次统计出链表中结点的个数,第二次我们就能找到倒数第k个结点了。但是面试官一般只要求遍历链表一次,这就需要另外一种解法了。

我们定义两个指针,第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针保持不动:从第k步开始,第二个指针也开始从链表的头指针开始遍历,由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点.。

public static Node FindKthtoTail(Node head, int k) {
		if (head == null || k == 0)
			return null;

		Node slow = head;
		Node fast = head;

		for (int i = 0; i < k - 1; i++)
			fast = fast.next;

		while (fast.next != null) {
			fast = fast.next;
			slow = slow.next;
		}
		return slow;

	}
相关题目:

1求链表的中间结点.如果链表的总数是奇数,返回中间结点;如果是偶数,返回中间两个结点的任意一个。为了解决这个问题,我们也可以定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步,当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间.

       2.判断一个链表是否又环,在上面已经有说到.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值