数据结构中有关链表的题目

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

/**
 * Created by wst on 2017/6/30.
 */
public class List_Algorithm {

    public static void main(String[] args) {
        Node n1 = new Node(1);
        Node n2 = new Node(2);
        Node n3 = new Node(3);
        Node n4 = new Node(4);
        Node n5 = new Node(5);
        Node n6 = new Node(6);
        n1.next = n2;
        n2.next = n3;
        n3.next = n4;
        n4.next = n5;
        n5.next = n6;
        Node n11 = n1;
        Node n12 = n2;
        Node n13 = n3;
        Node n14 = n4;
        Node n15 = n5;
        Node n16 = n6;
        n11.next = n12;
        n12.next = n13;
        n13.next = n14;
        n14.next = n15;
        n15.next = n16;
        n16.next = n13;
        List_Algorithm list_algorithm=new List_Algorithm();
        List_Algorithm list_algorithm1=new List_Algorithm();
       // System.out.println(list_algorithm.FindListLength(n1));
       // list_algorithm.printLinked(list_algorithm.revLinkedList(n1));
      // Node nx=list_algorithm.revLinkedList(n1);
       // list_algorithm.printLinked(n1);

        int k=0,k1=0;
        Node newNode1=n1;
        //list_algorithm.printLinked(n1);
        //list_algorithm.printLinked(list_algorithm.revLinkedList(n1));
       // Node newNode2=list_algorithm.revLinkedList(n1);
        //Node newNode3=list_algorithm1.revLinkedList(newNode2);
       // Node newNode4=list_algorithm1.revLinkedList(newNode3);
       // list_algorithm.printLinked(n1);
       // list_algorithm.printLinked(newNode1);
       // list_algorithm.printLinked(newNode2);
       // list_algorithm1.printLinked(newNode3);
       // list_algorithm.printLinked(newNode4);
     // list_algorithm.printLinked(list_algorithm.mergeSortedListRecsion2(n1,n13));
       // list_algorithm.revprintListRecsion(n1);
        System.out.println(list_algorithm.getFirstNodeInCycleHashMap(n11).data);

    }
    //求节点的个数
    public int FindListLength(Node node){
        if (node ==null)
            return 0;
        int sum=0;
        while(node!=null){
            sum=sum+1;
            node=node.next;
        }
        return sum;
    }
    //反转单链表,遍历链表,取下当前节点,在新链表中倒着链接。
    public Node revLinkedList(Node node1){
        Node node=node1;
        if(node==null||node.next==null)
            return node;
        else {
           Node preHead=null;
          // Node nextHead=null;
           while(node!=null) {
             Node nextHead=node.next;//取下当前节点前,防止链表断裂,将后面链表保存
             node.next=preHead; //取下当前节点,并链接新链表prehead
             preHead=node;      //保存当前节点
             node=nextHead;     //将取下节点后的链表,存回node.
           }
            return preHead;
        }
    }
    //使用递归
    public Node revLinkedList2(Node head){
        if(head==null||head.next==null)
            return head;
       Node newHead=revLinkedList2(head.next);
       head.next.next=head;
       head.next=null;
       return newHead;
    }
    //找到链表中的倒数的第K个节点
    //方法一。先统计出链表中的节点个数N,然后再找到第(N-k)个节点,就是倒数的第K个节点
    public Node FindRevNode(int k,Node head){
        int NodeNum=0;
        Node q=head;
        while (head!=null){
            NodeNum=NodeNum+1;
            head=head.next;
        }
        System.out.println(NodeNum);
        int flag=NodeNum-k;
        //System.out.println(flag);
        while (flag>0){
            q=q.next;
            //head=head.next;
            flag--;
        }
        return q;
    }
    //方法二、使用两个链表firstsecond,先让first链表走到正向的K个节点,此时两个节点的距离差刚好的K-1个,
    //然后两个链表同时向前移动,当first链表走到最后一个节点时,second的链表刚好访问到的是倒数第K的节点
    public Node FindRevNode2(int k,Node head){
        Node first=head;
        Node second=head;
        if(k<1||head==null)
            return null;
        while(k>1&&first!=null){
            first=first.next;
            k--;
        }
        if(k>1||first==null)//如果K大于链表的长度,那么此时first一定为null,所以返回null
            return null;
        while (first.next!=null){
            first=first.next;
            second=second.next;
        }
        return second;
    }
    //查找链表的中间节点,与上面相类似,只是first链表走两步,而second链表走一步,
    //first链表走到最后节点时,second链表就走到中间节点
    public Node FindMiddNode(Node head){
        if(head==null||head.next==null)
            return head;
        Node first=head;
        Node second=head;
        while (first!=null){
            first=first.next;
            second=second.next;
            if(first!=null)
                first=first.next;
        }
        return second;
    }
    //从尾部打印单链表,这种颠倒顺序的问题,我们应该想到栈,后进先出。所以,有两个方法,第一,
    //自己使用栈,第二就是让系统使用栈,也即是递归调用。
    public void revprintListStack(Node head){
        Stack<Node> stack=new Stack<>();
        while(head!=null){
            stack.push(head);
            head=head.next;
        }
        //System.out.println(stack.pop().data);
        while(!stack.isEmpty()){
            System.out.print(stack.pop().data);
        }
        System.out.println("");
    }
    //递归方法从尾部打印链表。
    public void revprintListRecsion(Node head){
        if (head==null)
            return;
        revprintListRecsion(head.next);
        System.out.print(head.data);
    }
    //合并链表。针对这个问题,要充分考虑好各种情况,当两个链表都为空时,或者
    //一个为空时,怎么去处理要注意。
    public Node mergeSortedList(Node head1,Node head2){
        Node newHead=null;
        if (head1==null)
            return head2;
        else if (head2==null)
            return head1;
        else {
            if (head1.data < head2.data) {
                newHead=head1;
                head1=head1.next;
            }
            else {
                newHead=head2;
                head2=head2.next;
            }
        }
        Node newHead2=newHead;
        while ((head1!=null)&&(head2!=null)){
            if(head1.data<head2.data){
                newHead2.next=head1;
                head1=head1.next;
              //  System.out.print(newHead2.data+"*");
            }else {
                newHead2.next=head2;
                head2=head2.next;
             //   System.out.print(newHead2.data+".");
            }
            newHead2=newHead2.next;
           // newHead2.next=null;
        }
        if (head1!=null)
         newHead2.next=head1;
        else
         newHead2.next=head2;
       // System.out.println("han");
        return newHead;
    }
    //递归实现合并,
    public Node mergeSortedListRecsion(Node head1,Node head2){
        if (head1==null)
            return head2;
        if (head2==null)
            return head1;
        Node newHead=null;
        if (head1.data<head2.data){
            newHead=head1;
            newHead.next=mergeSortedListRecsion(head1.next,head2);
        }else {
            newHead=head2;
            newHead.next=mergeSortedListRecsion(head1,head2.next);
        }
        return newHead;
    }
    //递归,不新建链表
    public Node mergeSortedListRecsion2(Node head1,Node head2){
        if (head1==null)
            return head2;
        if (head2==null)
            return head1;
        //Node newHead=null;
        if (head1.data<head2.data){
            head1.next=mergeSortedListRecsion(head1.next,head2);
            return head1;
        }else {
            head2.next=mergeSortedListRecsion(head1,head2.next);
            return head2;
        }
       // return newHead;
    }
    //判断单链表是否有环。如果链表有环,那么遍历改环的话将走不到头。为此我们想到是否可以,使用
    //两个链表,让first链表走两步,second链表走一步,那么first链表和second链表一定会再次相遇。
    //以此来判断是否有环
    public boolean hasCycle(Node head){
        if(head==null)
            return false;
        else {
            Node first=head;
            Node second=head;
            while (first.next!=null&&first!=null){//first来判断,当无环时更加节省时间复杂度
                first=first.next.next;
                second=second.next;
                //second=second.next;
                if(first==second)
                    return true;
            }
            return false;
        }
    }
    //判断两个单链表是否相交。如果两个链表相交于某一节点,那么这一节点后面的所有节点
    //都为两个链表共有(最差情况是只有最后一个节点相共有),因为从前面遍历不方便判断,
    // 因此我们从最差的情况判断,判断最后一个节点是否为两个链表共有,如果最差情况都满足
    //那么这两个单链表一定相交
    public boolean isIntersected(Node head1,Node head2){
        if(head1==null||head2==null)
            return false;
        else{
            while (head1.next!=null)
            {
                head1=head1.next;
            }
            while (head2.next!=null){
                head2=head2.next;
            }
            if (head1==head2)
                return true;
            else
                return false;
        }
    }
    //判断两个单链表相交的第一个节点,方法1.可以使用map来存储第一个链表,
    // 再通过contains.Key()方法来判断是否与第二个链表相同
    //方法二。可以使用栈来存储两个链表,然后弹栈比较两链表节点,当遇到最后一个不相等的节点时,
    //说明前一个节点就是相交的第一个节点
    //方法三。分被遍历两个链表,保存长度len和最后一个节点,若最后一个节点相等那么
    // 判断哪个链表要长一些,然后长的那个链表走len1-len2步,此时两个链表的长度就一样了,此时来
    //一起遍历,直到遇到相同的节点。
    public Node getFistCommonNode1(Node pHead1,Node pHead2){
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
    Stack<Node> stack1 = new Stack<>();
    Stack<Node> stack2 = new Stack<>();
    while(pHead1.next != null) {
        stack1.push(pHead1);
        pHead1 = pHead1.next;
        }
        stack1.push(pHead1);
        while (pHead2.next != null) {
        stack2.push(pHead2);
        pHead2 = pHead2.next;
        }
        stack2.push(pHead2);
        Node commonListNode = null;
        while (!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.peek() ) {
            stack2.pop();
            commonListNode = stack1.pop();
        }
        return commonListNode;
    }
    //方法一
    public Node getFirstCommonNode(Node pHead1,Node pHead2){
        Node head1=pHead1;
        Node head2=pHead2;

        HashMap<Node,Boolean> map=new HashMap<>();
        while (head1.next!=null){
            map.put(head1,null);
            head1=head1.next;
        }
        map.put(head1,null);
        while (head2!=null){
            if(map.containsKey(head2))
                return head2;
            head2=head2.next;
        }
        return null;


    }

    //已知单链表中存在环,求进入环的第一个节点
    //方法1.使用map来做
    //方法2.使用快慢指针runner来进行。
    public Node getFirstNodeInCycleHashMap(Node head){
            HashMap<Node,Boolean> map1=new HashMap<Node,Boolean>();
            //boolean flag=false;
           // nodeHashMap.put(head,0);
            while (head!=null){
                if(map1.containsKey(head)) {
                    return head;
                }
                else{
                    map1.put(head,true);
                head=head.next;
                }
            }
            return null;
    }

    //runner
//    first的速度是second的两倍。假设second移动到进入环的第一个节点,距离开始节点相差k,
//    那么first此时在环内距离进入环的第一个节点的距离是x(x=mod(k,环的长度length)),
//    此时second处于环中0步,first领先于secondx步,second落后于firstlength-x步,因此再次
//    相遇时(first追上second),需要走length-x(frist每次必second多走一步),因此这个相遇点
//    再向前走x步就到环入口。如果此时开始节点和second同时向前移动,那么必定会在环入口相遇。此时相遇
//    的节点就是,环的第一个节点。(k=x+m*length),所以若环很小,也满足。
    public Node getFirstNodeInCycleRunner(Node head){
        Node first=head;
        Node second=head;
        while (first!=null&&first.next!=null){
            first=first.next.next;
            second=second.next;
            if (first==second)
                break;
        }
        if(first==null||first.next==null)
            return null;
        first=head;
        while (first!=second){
            first=first.next;
            second=second.next;
        }
        return first;
    }
    //给定一个单链表,和一个节点beDeletedNode,要求实现时间复杂度为O(1),删除节点
    //beDeleteNode.对于链表,每个节点的结构都是一样的,所以我们可以要删除节点的下一个
    //节点,复制到该节点,然后删除下一个节点即可。但是要注意删除节点是最后一个节点的情况。
    // 这时候要单独考虑,因为其下一个节点为null。因此只能找到上一个节点,然后让其head.next=null
    // 来删除该节点(但此时的时间复杂度,就不为O(1),而是O(n)了,因此可以在
    // 删除最后一个节点标记为false)。
    public boolean deleteNode(Node head,Node beDeleteNode){
        if(beDeleteNode==null)
            return false;
        if (beDeleteNode.next!=null)//删除节点,除去最后一个节点的情况
        {
            beDeleteNode.data=beDeleteNode.next.data;//将下一节点复制给删除节点
            beDeleteNode.next=beDeleteNode.next.next;
            return true;
        }
        else {//删除的是最后一个节点的情况
            if(beDeleteNode==head)//链表中只有一个节点的情况
            {
                head = null;
                return true;
            }
            else {
                Node phead=head;
                while(phead.next!=beDeleteNode){//找到上一个节点
                    phead=phead.next;
                }
                phead.next=null;//删除该节点
                return true;
            }
        }

    }
    public void printLinked(Node head){
        while(head!=null) {
            System.out.print(head.data);
            head=head.next;
        }
        System.out.println("");
    }

}
class Node {
    public int data;
    public Node next;

    Node(int data) {
        this.data = data;
        this.next = null;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值