链表

单链表

Linked List链表 是一种有序的列表:

  1. 链表是 以结点的方式来存储,为链式存储
  2. 每个结点 包含data域,next域(指向下一结点)
  3. 链表的 各个结点不一定是连续存储
  4. 链表分为 带头节点 和 无头节点 的链表
  5. 添加节点: 头插法 与 尾插法

创建节点

  1. 使用一个 Node对象来代表结点,node中包含 data 和 next data;
  2. 定义一个 SingleLinkedList类 来管理链表
结点对象
//每一个对象 代表一个 节点
class HeroNode{
    public int no;
    public String name;
    public String nickname;
    public HeroNode next; //指向下一个节点(对象表示节点)

    public HeroNode(int no,String name,String nickname){
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }
}
初始化链表
class SingleLinkedList{
    //初始化头节点
    private HeroNode head = new HeroNode(0,null,null);
    public HeroNode getHead(){
        return head;
    }

    //添加节点方法
    public void add(HeroNode node){
        //先找到头节点 并赋值给 temp临时变量
        HeroNode temp = head;
        //1.遍历链表,找到最后
        while (true){
            if (temp.next==null)
                break;
            temp = temp.next;
        }
        //2.给最后的next赋值
        temp.next = node;
    }
}

增删改操作

找到待操作结点的前一个结点,然后进行 操作

删除,修改节点
public void delete(int no){
    Node temp = head;
    while (temp.next!=null){
        if (temp.next.no == no){
            temp.next = temp.next.next;
            return;
        }
        temp = temp.next;
    }
    System.out.println("未找到该编号结点");
}
public void update(Node newNode){
    Node temp = head;
    while (temp.next!=null){
        if(temp.next.no == newNode.no){
            temp.next.name = newNode.name;
            return;
        }
        temp = temp.next;
    }
    System.out.println("未找到该编号结点");
}
按编号顺序插入节点
public void addByOrder(Node node){
    Node temp = head;
    while (temp.next!=null){
        //按编号从小到大放入结点 1,2,4 -- 3
        if (temp.next.no > node.no){
            break;
        }
        if (temp.next.no==node.no){ //相同编号--更新
            node.next = temp.next.next;
            temp.next = node;
            return;
        }
        temp = temp.next;
    }
    //插入该节点
    node.next = temp.next;
    temp.next = node;
}
//打印链表
public void show(){
    if (head.next==null){
        System.out.println("空链表~");
        return;
    }
    Node temp = head.next;
    while (temp!=null){
        System.out.println(temp);
        temp=temp.next;
    }
}

单链表面试题

1. 求链表中节点的个数
public static int getLength(HeroNode head){
    if (head.next == null){
        System.out.println("空链表~");
        return 0;
    }
    int length=0;
    HeroNode temp = head;
    while (temp.next!=null){
        length++;
        temp=temp.next;
    }
    return length;
}
2. 查找链表中倒数第k个结点
public Node findLastNode(Node head,int index){
    //1.获取链表长度
    int length = getLength(head);
    if (index<=0 || index>length){
        System.out.println("该节点不存在");
        return null;
    }
    Node temp = head.next;
    //2. length-index = 结点位置   倒数第二个3-2=1
    for (int i = 0; i < length-index; i++) {
        temp = temp.next;
    }
    return temp;
}
3. 单链表反转
/*遍历原链表,头插法创建新链表*/
public void reverse(Node head){
    //1.链表只有一个结点或为空
    if (head.next==null || head.next.next==null){
        return ;
    }
    //2.创建反转链表
    //a.遍历原链表
    Node temp = head.next;  //存放遍历的结点
    Node temp2 = temp.next; //记录遍历的下一个结点
    Node tempHead = new Node(0,null);//新链表的头结点
    while (temp!=null){
        temp2 = temp.next; //记录下一个要遍历的结点
        //b.头插法 插入结点
        temp.next = tempHead.next;
        tempHead.next = temp;

        temp = temp2;
    }
    head.next = tempHead.next;
}
4. 单链表逆序打印
/*使用栈,在不破坏原有结构的情况下逆序输出链表*/
public void reversePrint(Node head){
    if (head.next==null){
        System.out.println("空链表");
        return;
    }
    //1.将结点全部压入链表
    Stack<Node> stack = new Stack();
    Node temp = head.next;
    while (temp!=null){
        stack.push(temp);
        temp = temp.next;
    }
    //2.弹出结点 并打印
    while (!stack.isEmpty()){
        System.out.println(stack.pop());
    }
}

双向链表

对比:

  1. 单链表查找方向只能是一个,双向链表可以前后查找
  2. 单链表不能 自我删除,需要靠temp前置结点。
  3. image
双向链表代码
class DoubleLinkedList{
    private Node2 head;
    public DoubleLinkedList(){
        this.head = new Node2(0,null);
    }
    /*增删改*/
    public void add(Node2 node){
        Node2 temp = head;
        //1.遍历到最后一个链表
        while (temp.next!=null){
            temp = temp.next;
        }
        temp.next = node;
        node.pre=temp;
    }
    public void addByOrder(Node2 node){
        Node2 temp = head;
        while (temp!=null){
            if (temp.no > node.no){  //a.小于当前结点,往前插入  1,2,4--3
                node.next = temp;
                node.pre = temp.pre;

                temp.pre.next = node;
                temp.pre = node;
                return;
            }
            if (temp.no == node.no){ //c.编号一致 更新改结点
                temp.name = node.name;
                return;
            }
            if (temp.next == null){  //b.插入到最后的情况
                temp.next = node;
                node.pre = temp;
                return;
            }
            temp = temp.next;
        }
    }
    //找到要修改的结点:进行更新/删除操作
    public void update(Node2 node){
        Node2 temp = head.next;
        while (temp!=null){
            if (temp.no == node.no){
                temp.name = node.name;
                System.out.println("更新完成");
                return;
            }
            temp = temp.next;
        }
        System.out.println("未找到该编号结点");
    }
    public void delete(int no){
        Node2 temp = head.next;
        while (temp!=null){
            if (temp.no == no){
                temp.pre.next = temp.next;//自我删除
                if (temp.next!=null) {    //若要删除的节点为最后一个节点 它没有后置节点
                    temp.next.pre = temp.pre;
                }
                System.out.println("删除完成");
                return;
            }
            temp = temp.next;
        }
        System.out.println("未找到该编号结点");
    }

    public void show(){
        if (head.next==null){
            System.out.println("空链表~");
            return;
        }
        Node2 temp = head.next;
        while (temp!=null){
            System.out.println(temp);
            temp = temp.next;
        }
    }
}

环形链表

单向环形链表

image

创建与遍历环形链表
//单向环形链表
class CircularLinkedList{
    public Node head;
    public CircularLinkedList(){
        head = new Node(0,null);
    }
    /*创建环形链表: temp一直指向最后一个结点*/
    public void add(int num){
        if (num<1){
            System.out.println("请输入正确num值");
            return;
        }
        Node temp = null; //记录最后一个结点位置
        for (int i = 1; i <= num; i++) {
            Node node = new Node(i,"环形链表");
            if (i==1){ //添加第一个结点的情况
                head = node;
                head.next = node; //指向自己构成环
                temp = head;
            }else {    //加入结点
                node.next = temp.next; //新插入的节点继承环
                temp.next = node;
                temp = node;
            }
        }
    }
    public void list(){
        if (head==null){
            System.out.println("空链表~");
            return;
        }
        Node temp = head;
        while (true){
            System.out.println(temp);
            temp = temp.next;
            if (temp==head){
                break;
            }
        }
    }
}

约瑟夫Josehu 问题:

有 n 个小孩做一圈,从第k个人开始报数,每次数m下, 看最后留下的是谁
【5个小孩,从第一个开始,每轮数2下; 1,2-->第二个小孩出去 第三个小孩重复上述】

  1. 创建temp节点,指向first的前一个(用于删除节点)
  2. first与temp 后移 k-1 次,准备报数
  3. while循环开始 出圈:
    • 每次 报数,first与temp 后移m-1
    • 弹出 first所指节点,first指向下一个(first=first.next; temp.next=first
    • temp=first 只剩一个节点,出圈完毕。
      image
代码实现
/**
 *  约瑟夫环问题
 * @param start 开始位置
 * @param no    每轮报几个数
 * @param num   总人数(环大小)
 */
public void Josehu(int start,int no,int num){

    if (start>num || no>num ||start<1 ||no<1){
        System.out.println("参数有误");
        return;
    }
    //1.初始化
        //a.创建环
    add(num);
        //b.移动到start开始位置 ,并创建temp指向开始位置的前一个
    Node temp = head;
    for (int i = 1; i < start; i++) { //从1开始
        head = head.next;
    }
    while (temp.next!=head){
        temp = temp.next;
    }
    System.out.println("移动后:"+"temp:"+temp+"\nhead:"+head);
    //2.遍历环,报数 出圈
    while (true){
        //a.报数 移动 k-1次
        for (int i = 0; i < no-1; i++) {
            head = head.next;
            temp = temp.next;
        }
        //b.出圈
        System.out.printf("编号为%d的小孩出圈\n",head.no);
        head = head.next;
        temp.next = head;
        //c.只剩最后一个结点
        if (temp==head){
            System.out.println("最后一个编号为%d的小孩出圈"+head.no);
            break;
        }
    }
}
posted @ 2022-02-06 17:07  simp1e1  阅读(25)  评论(0)    收藏  举报