有关于单链表的面试题

单链表的基础

单链表基础请见我的这一篇文章

遍历输出链表中的每一个节点

思路:直接对链表进行遍历,辅助指针每移动一个节点,就将该节点的数据输出出来,然后辅助指针指向下一个节点。

 public void show() {
        //先判断是否为空的链表
        if (head.next == null) {
            System.out.println("链表为空");
            return;
        }
        //需要借助一个辅助节点来遍历整个链表
        LinkedNode1 temp = head.next;
        while (true) {
            //如果已经遍历到最后一个节点之后,就可以跳出循环
            if (temp == null) {
                break;
            }
            System.out.println(temp);
            //输出后要将temp后移,找下一个节点,要不然会进入死循环
            temp = temp.next;
        }

    }

查找单链表中节点的个数

思路:直接对链表进行遍历,辅助指针每移动一个节点,count就+1,然后指向下一个节点,最后返回count就是节点数目

public int countNode(){
        LinkedNode1 temp=head;
        int count=0;
        while(true){
            if(temp.next==null){
                break;
            }
            count++;
            temp=temp.next;
         }
        return count;
    }

输出倒数第k个节点

思路:

  • 先遍历出整个链表中有多少的节点sum
  • 然后倒数第k个节点就是正数第index=sum-k+1个节点
  • 设置一个计数变量count,在遍历时进行count++
  • 只要在此遍历时有index==count,故说明此节点就是我们要找的倒数第k个节点,输出此节点即可
public void returnK(int k){
        int sum=countNode();//调用了计数的方法来求出总的节点数
        int index=sum-k+1;
        LinkedNode1 temp=head;
        int count=0;
        if(k>sum||k<=0){
            System.out.println("链表中没有这么多的数或者请输入大于0的值");
            return;
        }
        while(true){
            if(count++ == index){
                System.out.println(temp);
                break;
            }
            temp=temp.next;
        }
    }

对单向链表进行反转

单项链表反转图
如图所示。至于为什么要引入temp节点,主要是因为在将原始链表中的节点移动到新的链表后,原始链表将会失去这个节点,而指向这个节点的temp也被移走了,因此要引入cur节点来指向原始链表的下一个节点,进行遍历。

    //链表的头尾反转
    /*思路:1重新创建一个头节点reverseHead
    * 2遍历原始的链表,每遍历一个就把这个元素取出,放到reverseHead的最前面
    * 3最后将原始链表的头节点指向reverseHead的next节点
    * */
    public void reverse(LinkedNode1 head){
        //创建一个新的节点
        LinkedNode1 reverseHead=new LinkedNode1(0,"","");
        LinkedNode1 temp=head.next;
        LinkedNode1 cur=null;
        while(temp!=null){
            //因为temp在取出元素时就不能指向下一个节点,故需要领取辅助节点来记住temp.next的位置
            cur=temp.next;
            //只要原始链表中仍然有元素,就把当前元素放到reverseHead的下一个节点
            //第一步:把temp所指的当前元素指向reverseHead的后面那个节点。
            temp.next=reverseHead.next;
            //第二步,将reverseHead指向temp节点
            reverseHead.next=temp;
            //利用cur辅助节点来对原始链表上进行遍历
            temp=cur;
        }
        //最后一步,将原始链表的头节点指向新链表头节点的下一个节点。
        head.next=reverseHead.next;
        //调用一下方法直接显示一下
    }

对单链表中的数据进行逆序打印

思路

  1. 先将链表反转,在正着遍历输出。但是会破坏原始链表!不推荐
  2. 利用栈结构的特点,先进后出。只要按顺序将链表进行入栈操作,然后再将栈中的数据进行弹栈,就可以实现逆序打印
    public void reversePrint(LinkedNode1 head){
        //创建辅助指针来遍历链表
        LinkedNode1 temp=head.next;
        if(temp==null){
            System.out.println("链表为空!");
            return;
        }
        //新建一个栈
        Stack<LinkedNode1> stack = new Stack<>();
        while(temp!=null){
            //只要链表中有元素,就往栈中压栈
            stack.push(temp);
            temp=temp.next;
        }
        while(!stack.empty()){
            //只要栈中还有元素就给我弹栈!
            System.out.println(stack.pop());
        }
    }

合并两个有序的单链表,合并之后仍然有序。

基本思路:
第一次合并图解
从图中可以看出,第一次合并时,只需要先判断出那个节点的数更小,确定要连接的节点之后,

  1. temp.next=cur1即:先指向此节点
  2. temp=temp.next; 让合并之后的辅助指针temp指向cur1
  3. cur1=cur1.next让cur1节点后移
    当连到第二个链表时,
  4. temp.next=cur2即:先指向此节点
  5. temp=temp.next; 让合并之后的辅助指针temp指向cur2
  6. cur2=cur2.next让cur2节点后移
    以此类推:当两个链表长度不相同时,先比较相同的部分,剩下多的那个,肯定是比前面的都大,不需要比较了,直接加在新链表的后面即可,让temp指针指向即可。
public LinkedNode1 combine(LinkedNode1 node1, LinkedNode1 node2) {

       LinkedNode1 temp = head;
       LinkedNode1 cur1 = node1.next;
       LinkedNode1 cur2 = node2.next;

       while (cur1 != null && cur2 != null) {
           if (cur1.no <= cur2.no) {
               temp.next = cur1;
               temp = temp.next;
               cur1 = cur1.next;

           } else {
               temp.next = cur2;
               temp = temp.next;
               cur2 = cur2.next;
           }
       }
       temp.next = cur1 == null ? cur2 : cur1;
       return head.next;
   }

二刷心得:

算法真的是需要多次练习,只要理解了,然后在量上慢慢积累,就可以很快写出来

package com.njupt.List.Test;

import java.util.Stack;

/**
 * Creat with IntelliJ IDEA
 *
 * @Auther:倔强的加瓦
 * @Date:2021/12/23/20:41
 * @Description:面试必会的几个关于链表的笔试题目3
 */
public class ListHomeWork {
    public static void main(String[] args) {
       /* ListOO list = new ListOO();
        for(int i=1;i<=10;i++){
            NodeOO nodeOO = new NodeOO(i, i + "号节点");
            list.add(nodeOO);
        }
        list.show();
        System.out.println();
        System.out.println("倒数第2个节点");
        list.countFromEnd(2);

        ListOO list2=list.reverse(list);
        System.out.println();

        System.out.println("=========实现逆序打印========");
        ListOO listBack = new ListOO();
        for(int i=1;i<=10;i++){
            NodeOO nodeOO = new NodeOO(i, i + "号节点");
            listBack.add(nodeOO);
        }
        listBack.reversePrint(listBack);
        System.out.println();
        System.out.println("=====打印之后,并没有改变原来的链表顺序====");
        listBack.show();*/
        ListOO list1 = new ListOO();
        for(int i=1;i<=11;i=i+2){
            NodeOO nodeOO = new NodeOO(i, i + "号节点");
            list1.add(nodeOO);
        }
        list1.show();


        ListOO list2 = new ListOO();
        for(int i=2;i<=18;i=i+2){
            NodeOO nodeOO = new NodeOO(i, i + "号节点");
            list2.add(nodeOO);
        }
        list2.show();
        System.out.println("开始测试两个链表融合");
        ListOO combine = combine(list1, list2);
        combine.show();
    }

    public static ListOO combine(ListOO list1,ListOO list2){
        NodeOO temp1=list1.head;
        NodeOO temp2=list2.head;

        ListOO list = new ListOO();

        NodeOO newHead=list.head;
        NodeOO temp=newHead;
        NodeOO cur1=temp1.next;
        NodeOO cur2=temp2.next;
        while (cur1!=null&&cur2!=null){
            temp1=cur1;
            temp2=cur2;
            if(temp1.id<temp2.id){
                temp.next=temp1;
                temp=temp.next;
                cur1=cur1.next;
            }else {
                temp.next=temp2;
                temp=temp.next;
                cur2=cur2.next;
            }

        }

        if(temp1.next==null){
            temp.next=temp2;
        }else {
            temp.next=temp1;
        }
        return list;
    }
    //
}
class ListOO{
    public NodeOO head=new NodeOO(0,"");

    //往链中添加数据
    public void add(NodeOO node){
        if (head.next==null){
            head.next=node;
            System.out.println(node+"添加完毕!");
            return;
        }
        NodeOO temp=head;
        while (temp.next!=null){
            if(temp.next.id<node.id){
                temp=temp.next;
            }else {
                //完成添加操作
                node.next=temp.next;
                temp.next=node;
                System.out.println(node+"添加完毕!");
                return;
            }
        }
        //完成添加操作
        temp.next=node;
        System.out.println(node+"添加完毕!");
    }
    //遍历链表中的所有数据并且返回链表中节点的个数
    //记录链表的长度
    public int show(){
        int count=0;
        if(head.next==null){
            System.out.println("当前链表为空!节点数为0");
            return count;
        }
        NodeOO temp=head;
        while (temp.next!=null){
            temp=temp.next;
            count++;
            System.out.print(temp+"-->");
        }
        System.out.println("共有节点数为:"+count);
        return count;
    }

    //输出倒数第2个节点
    public void countFromEnd(int num){
        if(show()<num){
            System.out.println("当前节点查找数错误,链表中只有"+show()+"个节点!");
            return;
        }
        NodeOO slow=head;
        NodeOO fast=head;
        for(int i=0;i<num;i++){
            fast=fast.next;
        }
        while (fast.next!=null){
            slow=slow.next;
            fast=fast.next;
        }
        System.out.println("倒数第个"+num+"节点是:"+slow.next);
    }
    //对单向链表进行反转
    public ListOO reverse(ListOO listOO){
        System.out.println("反转之前:");
        int i=listOO.show();
        if(i==0){
            System.out.println("当前链表为空,不能反转");
            return null;
        }else if(i==1){
            System.out.println(listOO.head.next);
            return listOO;
        }else {
            NodeOO temp=listOO.head.next;
            NodeOO newHead=new NodeOO(0,"");
            while (temp!=null){
                //先让辅助指针向后移动一个
                NodeOO cur=temp.next;
                temp.next=newHead.next;
                newHead.next=temp;
                //在把辅助指针赋值为temp
                temp=cur;
            }
            //到此处已经反转成功了,此时需要将head头节点换回来
            listOO.head=newHead;
            System.out.println("反转之后的链表为:");
            listOO.show();
            return listOO;
        }
    }
    //对单向链表的数据进行逆序打印:思路是为了不改变链表的结构,需要借助stack栈来实现先进后出
    public void reversePrint(ListOO listOO){
        int length = listOO.show();
        if(length==0){
            return;
        }else if(length==1){
            System.out.println(listOO.head.next);
            return;
        }
        Stack<NodeOO> stack = new Stack<>();
        NodeOO temp=listOO.head.next;
        while (temp!=null){
            stack.push(temp);
            temp=temp.next;
        }
        System.out.println("逆序打印的结果为:");
        while (!stack.isEmpty()){
            System.out.print(stack.pop()+"-->");
        }
    }



}
class NodeOO{
    public int id;
    public String name;
    public NodeOO next;

    public NodeOO(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "NodeOO{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值