最全数据结构链表汇总(包括腾讯百度大厂经典面试题以及解析)

链表

链表介绍以及基本增删改查

  • 链表是有序的列表,但是它再内存中是存储如下
  • 初始化,和添加 基础操作
package com.data;


public class SingleLinkListDemo {
    public static void main(String[] args) {
        SingleLinkList singleLinkList=new SingleLinkList();
        singleLinkList.addNode(new Hero(1,"宋江","及时雨"));
        singleLinkList.addNode(new Hero(2,"卢俊义","玉麒麟"));
        singleLinkList.addNode(new Hero(3,"吴用","智多星"));
        singleLinkList.addNode(new Hero(4,"林冲","豹子头"));
        singleLinkList.list();
    }
}
class SingleLinkList{
    //初始化
    Hero head=new Hero(0,"","");
    //往尾部添加节点
    public void addNode(Hero hero){
        Hero temp=head;
        while (true){
            if(temp.next==null)break;
            temp=temp.next;
        }
        temp.next=hero;
    }
    //遍历节点
    public void list(){
        Hero temp=head.next;
        if(temp==null){
            System.out.println("该链表为空");
            return;
        }
        while (true){
            if(temp==null)break;
            System.out.println(temp);
            temp=temp.next;
        }
    }
}
class Hero{
    public int no;
    public String name;
    public String nickName;
    public Hero next;
    public Hero(int no,String name,String nickName){
        this.no=no;
        this.name=name;
        this.nickName=nickName;
    }


    @Override
    public String toString() {
        return "Hero{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

单链表小结

  1. 链表是以节点的方式来存储,是链式存储
  2. 每个节点包含data域,next域:指向下一个节点
  3. 链表的各节点不一定是连续存储
  4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定

单链表面试题

1, 求单链表中有效节点个数
2, 查找单链表中的倒数第k个节点【新浪面试题】
3,单链表的反转【腾讯面试题】
4, 从尾到头打印单链表【百度,要求方式一:反向遍历。方式二:Stack栈】
5, 合并两个有序的单链表,合并之后的链表仍然有序

题解

  • 求单链表中有效节点个数
public int getLength(){
    int length=0;
    Hero temp=head;
    while (true){
        if(temp.next==null)break;
        length++;
        temp=temp.next;
    }
    return length;
}
  • 查找单链表中的倒数第k个节点【新浪面试题】

  • 思路:先获取长度得到size-k;

   //查找单链表中的倒数第k个节点
public Hero getIndexNode(int index){
    Hero temp=head.next;
    int length=this.getLength();
    boolean flag=false;
    int count=0;
    while(true){
        if(temp==null)break;
        if(count==length-index){
            flag=true;
            break;
        }
        count++;
        temp=temp.next;
    }
    if(flag)return temp;
    else System.out.println("没有找到");
    return null;
}
  • 单链表的反转【腾讯面试题】
public void reverseList(){
    Hero newListHead=new Hero(0,"","");
    Hero temp=head.next;
    Hero next;
    while (temp!=null){
        next=temp.next;
        temp.next=newListHead.next;
        newListHead.next=temp;
        temp=next;
    }
    head.next=newListHead.next;
}
  • 从尾到头打印单链表【百度,要求方式一:反向遍历。方式二:Stack栈】

  • 思路:方式1:先反转后打印,但是会破坏原来的单链表的结构,不建议。

  • 方式2:将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果。

//采取方式2
//从尾到头打印单链表
public void reversePrint(){
    Hero temp=head.next;
    Stack<Hero> stack=new Stack<>();
    while (temp!=null){
        stack.push(temp);
        temp=temp.next;
    }
    while (!stack.empty()){
        System.out.println(stack.pop());
    }
}
  • 练习

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

static private SingleLinkList merge(SingleLinkList list1,SingleLinkList list2){
    Hero temp1=list1.head.next;
    Hero temp2=list2.head;
    boolean flage=true;
    while (temp1!=null) {
        while (temp1.no >= temp2.next.no) {
            temp2 = temp2.next;
            if (temp2.next == null) {
               // System.out.println("没有找到");
                flage = false;
                break;
            }
        }
        Hero next = temp1.next;
        if (flage) {
            temp1.next = temp2.next;
            temp2.next = temp1;
            temp1 = next;
            continue;
        } else {
            temp2.next = temp1;
            break;
        }
    }
    return list2;
}

双链表

管理单链表的确定分析

  • 管理单链表的确定分析:
  1. 单向链表查找的方向只能是一个方向,而双链表可以向前或者向后查找。
  2. 单链表不能自我删除,需要辅助节点,而双链表相反,所以我们单链表删除节点总是找到temp,temp是待删除节点的前一个节点。
  • 遍历 方式和单链表一样,只是可以向前,也可以向后查找

  • 添加 (默认添加到双向链表的最后)

  • 先找到双向链表的最后这个节点

 temp.next=newNode
 newNode.pre=temp
  • 修改 思路和单链表一样

  • 删除

  • 因为是双链表可以自我删除不需要辅助节点

    单项环形链表(图解)

在这里插入图片描述

单向环形链表应用场景

Josephu(约瑟夫,约瑟夫环)问题

  • 设编号为1,2…n的n个人围坐在一起,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,此此类推,直到所有人出列为止,由此产生一个出队编号的序列。
    • 构建一个单项的环形链表思路

      1. 先创建第一个节点,让first指向该节点,并形成环形
      2. 后面当我们每创建一个新的节点,就把该节点,加入到已有的环形链表中即可
    • 遍历环形链表

      1. 先让一个辅助指针变量curBoy,指向first节点
      2. 然后通过一个while循环遍历该环形链表即可curBoy.next==fisrt结束。
package com.data;


public class CircleLinkList {
    public static void main(String[] args) {
        CircleList circleList=new CircleList();
        circleList.addNode(5);
        circleList.show();
    }
}
class CircleList{
    Boy first=new Boy(0);
    Boy cur=new Boy(0);
//增加节点
    public void addNode(int n){
        if(n<1){
            System.out.println("创建循环链表数据有误");
        }
        for(int i=1;i<n+1;i++){
            if(i==1){
                first.no=i;
                first.next=first;
                cur=first;
            }else {
                Boy newNode=new Boy(i);
                cur.next=newNode;
                newNode.next=first;
                cur=cur.next;
            }
        }
    }
//打印链表
    public void show(){
        cur=first;
        while (true){
            if(cur.next==first){
                System.out.println(cur.no);
                break;
            }
            System.out.print(cur.no+"->");
            cur=cur.next;
        }
    }
}
class Boy{
    public int no;
    public Boy next;
    public Boy(int no){
        this.no=no;
    }
}

解决约瑟夫环的问题

  • 设编号为1,2…n的n个人围坐在一起,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,此此类推,直到所有人出列为止,由此产生一个出队编号的序列。
    • 图解
      在这里插入图片描述

    • 代码

public void yuesefu(int start,int num,int sum){
    if(start>sum||num>sum||sum<1) {
        System.out.println("参数不合法");
        return;
    }
    //开始添加节点
    addNode(sum);
    Boy helper=new Boy(0);
    helper=cur;
    //找到开始的节点
    while (true){
        if(first.no==start)break;
        helper=helper.next;
        first=cur.next;
    }
    while (true){
        if(first.next==first){
            System.out.println("最后留下来的是"+helper.no);
            break;
        }
        //循环到规定之后的节点
        for(int i=0;i<num-1;i++){
            helper=helper.next;
            first=first.next;
        }
        //取出节点
        System.out.println(first.no+"->");
        first=first.next;
        helper.next=first;
    }
}
发布了29 篇原创文章 · 获赞 10 · 访问量 7479

猜你喜欢

转载自blog.csdn.net/qmqm33/article/details/104127528