链表和双线链表

单链表

1.创建一个Node类

//    head不能动,头节点作用是表示链表的头
    private Node head;
// 在linkedList类写一个Node的成员内部类
private class Node {
    private int data;
    private Node next;

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

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }
}

2.头插法

//    头插法
    public void addFirst(int data) {
//        首先创建一个节点,要头插的结点
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
            return;
        }
        newNode.next = head;
        head = newNode;
    }

3.尾插法

//    尾插法
public void addLast(int data) {
    //        首先创建一个节点
    Node newNode = new Node(data);
    if (head == null) {
        head = newNode;
        return;
    }
    //        head不能动,需要一个辅助指针temp,遍历完链表
    Node temp = head;
    while (temp.next != null) {
        temp = temp.next;//遍历链表
    }
    temp.next = newNode;
}

4.指定位置插入

//    指定位置插入
    public void addByOrder(int data, int position) {
        //        首先创建一个节点
        Node newNode = new Node(data);
        if (position == 0) {
//            头插法
            newNode.next = head;
            head = newNode;
            return;
        }
//        position是size的话就是尾插法
        if (position==size()){
            addLast(data);
            return;
        }
//        head不能动,需要一个辅助指针temp找的要插入位置的亲一个结点即temp
        Node temp = head;
        int curPosition = 0;
        while (temp.next != null && curPosition < position - 1) {
            temp = temp.next;
            curPosition++;
        }
        newNode.next = temp.next;
        temp.next = newNode;
    }

5.查找key是否在单链表中

//    查找key是否在单链表中
public boolean getKey(int key) {
    if (head.next == null) {
        System.out.println("链表为空~~~");
        return false;
    }
    Node temp = head.next;
    while (temp != null) {
        if (temp.data == key) {
            return true;
        }
        temp = temp.next;
    }
    return false;
}

6.链表长度

//    链表长度
public int size() {
    Node temp = head;
    int count = 0;
    while (temp != null) {
        count++;
        temp = temp.next;
    }
    return count;
}

7.删除数据

//    删除数据
    public boolean deleteByOrder(int key){
        Node temp=head;
//        找到前一个节点
        while (temp.next!=null){
            if (temp.next.data==key){
                temp.next=temp.next.next;
                return true;
            }
            temp=temp.next;
        }
        return false;
    }

8.打印链表

//    打印链表
public void display() {
    Node temp = head;
    while (temp != null) {
        System.out.print(temp.data + " ");
        temp = temp.next;
    }
    System.out.println();
}

9.查找链表中的倒数第index的结点

//    查找链表中的倒数第index的结点
//    接收head结点和一个index
//    index表示是倒数第index个结点
//    先把链表从头到尾遍历,得到总长度size
//    得到size后,从链表的第一个开始遍历(size-index)个,就可以找到
//    如果找到了,返回该结点,否则返回null
    public static HeroNode findLastIndexNode(HeroNode head, int index) {
        if (head.next == null)
            return null;
//        第一个遍历得到链表的长度
        int sizes = size();
//        第二次遍历size-index位置,就是我们的倒数的第k个结点
//        做index的检验
        if (index < 0 || index > sizes)
            return null;
//        定义辅助变量,for循环定位倒数的index
        HeroNode cur = head.next;//3-1=2
        for (int i = 0; i < sizes - index; i++) {
            cur = cur.next;
        }
        return cur;
    }

10.单链表反转

//   将单链表反转
    public void reverseList(HeroNode head) {
//        当前链表为空,或者只有一个节点,无需反转,直接返回
        if (head.next == null || head.next.next == null)
            return;
//        定义辅助变量,遍历原来的链表
        HeroNode cur = head.next;
//        指向当前节点cur的下一个节点
        HeroNode next= null;
//        定义哨兵结点方便给后面找到头节点的位置
        HeroNode reverseHead = new HeroNode(-1, "", "");
//        遍历原来的链表,每遍历一个结点,将其取出,并放在新的链表reverseHead的最前端
        while (cur != null) {
            next = cur.next;//先暂时保存当前节点的下一个节点,后面需要使用
            cur.next = reverseHead.next;//将cur的下一个结点指向新的链表的最前端
            reverseHead.next = cur;//将cur连接到新的链表上
            cur = next;//cur后移
        }
//        将head.next指向reverseHead.next,实现单链表的反转
        head.next = reverseHead.next;

    }

11.逆序打印单链表

//    逆序打印单链表,用栈的数据结构
    public void reversePrint(HeroNode head) {
        if (head.next == null)
            return;
//        创建栈,将各个节点压入栈中
        Stack<HeroNode> stack = new Stack<>();
        HeroNode cur = head.next;
//        入栈
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;//后移,便于压入下一个节点
        }
//        出栈
        while (stack.size() > 0) {
            System.out.println(stack.pop());//先进后出
        }
    }

双向链表

双向链表的尾插法和修改和单链表一样

1.指定的位置插入

//    根据排名插入到指定的位置
//    如果有这个排名,添加失败,给出提示
    public void addByOrder(HeroNode2 newHeroNode) {
//        头节点不能动,仍然通过一个辅助指针来帮助找到添加的位置
//        因为单链表,我们找到的temp是位于添加位置的前一个结点,否者插入不了
        HeroNode2 temp = head;
        boolean flag = false;// flag标志添加的编号,默认false
        while (true) {
            if (temp.next == null)//temp已经在链表最后了
                break;
            if (temp.next.no > newHeroNode.no)//位置找到,temp的后面插入,该节点在temp和temp.next之间
                break;
            else if (temp.next.no == newHeroNode.no) {//编号已经存在
                flag = true;//编号存在
                break;
            }
            temp = temp.next;//后移temp,遍历链表

        }
//        判断flag的值
        if (flag)//不能添加,编号已经存在
            System.out.printf("准备插入的英雄编号%d已经存在,不能添加", newHeroNode.no);
        else {
            newHeroNode.next = temp.next;
            temp.next = newHeroNode;
            newHeroNode.pre = temp;
            if (newHeroNode.next != null) {
                newHeroNode.next.pre = newHeroNode;
            }
        }

    }

2.删除数据

//    对于双向链表,直接找到要删除的结点即可,自我删除
    public void delete(int no) {
        if (head.next == null) {
            System.out.println("链表为空,无法删除~~~");
            return;
        }
//        辅助指针temp
        HeroNode2 temp = head.next;
        boolean flag = false;//标志是否找到待删除结点
        while (true) {
            if (temp == null)//已经在链表的最后了
                break;
            if (temp.no == no) { //比较两节点的no
//                找到待删除结点的前一个结点temp
                flag = true;
                break;
            }
            temp = temp.next;//temp后移,遍历链表
        }
//        判断flag
        if (flag) {//找到
            temp.pre.next = temp.next;
//            如果要删除的是最后一个节点,要temp.next是否为空,否则空指针异常
            if (temp.next != null)
                temp.next.pre = temp.pre;
        } else {
            System.out.printf("要删除的%d结点不存在\n", no);
        }
    }

3.

posted @ 2023-11-25 16:58  MGLblog  阅读(20)  评论(0)    收藏  举报