单链表的相关题目

1.删除链表中给定值val的所有结点

public void removeall(int key) {
        //由于是删除链表中所有和key值相同的结点,所以可以设置两个ListNode类型的数据,一个在前面,一个在后面.
        //直到前面的走到链表的最后,这样完成了遍历.
        //先判断一下这个链表是否为空
        if(head==null){
            System.out.println("链表为空");
            return;
        }
        //在判断了不为空之后
        ListNode cur1=head;
        ListNode cur2=head.next;
        //遍历结束的条件是cur2==null
        while(cur2==null){
            if(cur2.val==key){
                //如果相等了,进行删除
                cur1.next=cur2.next;
                cur2=cur2.next;
            }
            else{
                //不相等的话,进行后移就好
                cur1=cur2;
                cur2=cur2.next;
            }
        }
        //结束了循环之后,还要判断第一个结点是否重复
        if(head.val==key){
            head=head.next;
        }
    }

2.反转一个链表,首先画一个图介绍一下什么叫反转一个链表.

可以看到在反转了之后,第一个结点变成了最后一个结点,最后一个结点编成了第一个结点.那么可以有两种思路完成这个反转,1.首先拿到最后一个结点,然后从第一个结点开始,以最后一个结点为头结点进行尾插.2.拿到第一个结点,以第一个结点未尾结点进行头插.

 public ListNode reverseList(){
        //首先判断是否是空表和是否是只有一个结点\
        if(head==null){
            System.out.println("空表,无法反转");
            return null;
        }
        if(head.next==null){
            return null;
        }
        //开始头插
        ListNode cur1=head.next;
        head.next=null;
        while(cur1!=null){
            ListNode cur2=cur1.next;
            cur1.next=head;
            head=cur1;
            cur1=cur2;
        }
        return head;
    }

 3.给定一个带有头结点head的非空链表,返回链表的中间结点.如果有两个结点,则返回第二个结点.

 public ListNode middleNode(){
        //一个生活中的实例,A的速度是1,B的速度是2,当B到达终点时,A行走的距离是B的一半.
        //所以根据这个现象,可以设置两个ListNode类型的变量一个一次走两步,一个一次走一步,当速度快的
        //走到尽头时,速度慢的刚好走到中间
        ListNode cur1=head.next;
        ListNode cur2=head.next.next;
        while(cur2.next==null||cur2==null){
         cur1=cur1.next;
         cur2=cur2.next.next;
        }
        return cur1;
    }

4.输入一个链表,输出该链表中倒数第K个结点的数据.

这个题目和上面一个题目可以用同一种方法求解,求导数第k个结点.有两种常想到的思路,思路一:首先遍历链表求出链表的节点个数N,倒数第K个结点就是顺序的第N-K+1个结点,然后遍历到第N-K+1个结点即可.但这种方法需要进行两次遍历.效率较低.思路二:和上一道题目一样,设置两个ListNode类型的变量cur1和cur2,让cur1比cur2多走K-1步,然后让cur1遍历链表,当cur1指向最后一个结点时.cur2指向的就是倒数第k个结点.具体代码如下:

 public ListNode getNode(int k){
        //首先设置cur1和cur2
        ListNode cur1=head;
        ListNode cur2=head;
        if(head==null){
         system.out.println("链表为空");
         return null;
         }
        for(int i=1;i<k;i++){
            cur2=cur2.next;
        }
        //这里可以开始循环
        while(cur2.next!=null){
            cur2=cur2.next;
            cur1=cur1.next;
        }
        return cur1;

    }

5.将两个有序链表合成为一个有序链表并返回,新链表是通过拼接给定的两个链表的所有结点组成的.两个有序链表都是升序的.

这一题的思路比较清晰,因为给定的链表都是有序的.可以设置cur1和cur2,遍历两个链表,比较数值区域的大小,然后进行拼接即可.

public static MySingleList.ListNode totalList(MySingleList.ListNode head1,MySingleList.ListNode
                                                  head2)
    {
       //设置一个傀儡结点
       MySingleList.ListNode newhead=new MySingleList.ListNode(-1);
       MySingleList.ListNode cur=newhead;
       //任何一个结点为空时,就要停止遍历
        while(head1!=null&&head2!=null){
            if(head1.val<head2.val){
                 cur.next=head1;
                 head1=head1.next;
                 cur=cur.next;

            }
            else{
                cur.next=head2;
                head2=head2.next;
                cur=cur.next;
            }
        }
        if(head1!=null){
            cur.next=head1;
        }
        if(head2!=null){
            cur.next=head2;
        }
        return newhead.next;
    }

6.编写代码,以给定值X为基准将链表分为两部分,所有小于X的结点排在大于或者等于X的结点之前.

可以设置一个cur来遍历链表,将数据域小于X的结点放在一个创建的链表中,将数据域大于X的结点放在另一个创建的链表中,然后将两个链表连接起来即可.具体代码如下:

public ListNode getXList(int x){
        //首先需要panduan
        ListNode s1=null;
        ListNode s2=null;
        ListNode s3=null;
        ListNode s4=null;
        ListNode cur=head;
        //这里要遍历完链表
        while(cur!=null){
            if(cur.val<x){
                //还要判断是否是第一个结点
                if(s1==null){
                    s1=cur;
                    s2=cur;
                }
                else{
                    s2.next=cur;
                    s2=s2.next;
                }
            }
            else{
                if(s3==null)//同样还是要判断是否是头结点
                {
                    s3=null;
                    s4=null;
                }
                else{
                    s4.next=cur;
                    s4=s4.next;
                }
            }
            cur=cur.next;
        }
        //在经过循环之后,接下俩就是需要连接.
        //连接也有多种情况
        //1.两个链表都有结点
        if(s1==null){
            return s3;
        }
        s2.next=s3;
        if(s3!=null){
            s4.next=null;
        }
        return s1;
    }

7.链表的回文结构

如何判断上述链表是回文结构呢?可以先找到中间结点,然后把中间结点之后的链表进行翻转,最后依次比较即可.(同时要注意节点个数的奇偶的不同)具体代码如下:

public boolean iscircle(){
      if(head==null){
      System.out.println("链表为空")
      return false;
     }
     //总的分为三步
        //1.找到中间结点,按照前面的方法即可
        ListNode cur1=head;
        ListNode cur2=head;//这个结点的速度较快
        while(cur2!=null&&cur2.next!=null){
            cur1=cur1.next;
            cur2=cur2.next.next;
        }
        //此时找到了中间结点,接着翻转
        ListNode cur3=cur2.next;
        while(cur3!=null){
            ListNode cur4=cur3.next;
            cur3.next=cur2;
            cur2=cur3;
           cur3=cur4;
        }//这里就翻转完了.
        //接着进行比较操作,此时cur2指向的是最后一个结点.
        //两个相同时就停止
        while(cur1!=cur2){
            if(cur1.val!= cur2.val){
                return false;
            }
            if(cur1.next==cur2.next){
                return true;
            }
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return true;
    }

8.输入两个链表,找出他们的第一个公共结点. 如图两个链表有公共结点.

如何才能够找到两个链表的结点呢?通过观察这个图形可以发现,两个链表的结点个数的差异在未相交之前因此可以通过节点个数相减来确定某个链表需要先遍历的步数,然后同时遍历,走到相同结点时,就找到了第一个公共结点. 

 public static MySingleList.ListNode sameNode(MySingleList.ListNode headA,MySingleList.ListNode headB){
       //先判断有没有空的链表
       if(headA==null||headB==null){
           return null;
       }
       int count1=0;
       int count2=0;
       MySingleList.ListNode cur1=headA;
       MySingleList.ListNode cur2=headB;
       while(cur1!=null){
           count1++;
           cur1=cur1.next;
       }
       while(cur2!=null){
           count2++;
           cur2=cur2.next;
       }
       //然后相减,得到相差的步数
       int len=count1-count2;
       if(len<0){
           cur1=headB;
           cur2=headA;
           len=count2-count1;
       }
       //这里进行移动
       for(int i=0;i<len;i++){
           cur1=cur1.next;
       }
       while(cur1!=cur2){
           cur1=cur1.next;
           cur2=cur2.next;
       }
       if(cur1==null){
           return null;
       }
       return cur1;
   }


 


 

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值