第4讲 链表

81 阅读3分钟

单链表

是一个有序的列表,前一个节点存在后一节点的地址信息的链式结构。

image.png

小结:

  1. 链表是以节点的方式来存储,是链式存储

  2. 每个节点包含 data 域, next 域:指向下一个节点.

  3. 如图:发现链表的各个节点不一定是连续存储.

  4. 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定。

链表逻辑结构示意图:

image.png

public class SingleLinkedListDemo {

    public static void main(String[] args) {
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        singleLinkedList.addByOrder(new HeroNode(7,"林冲","豹子头"));
        System.out.println("打印");
        singleLinkedList.show();
        singleLinkedList.addByOrder(new HeroNode(2,"周杰伦","zjj"));
        singleLinkedList.addByOrder(new HeroNode(5,"林俊杰","ljj"));
        System.out.println("打印");
        singleLinkedList.show();
        singleLinkedList.addByOrder(new HeroNode(8,"李宗盛","鬼才"));
        System.out.println("打印");
        singleLinkedList.show();
////        singleLinkedList.update(new HeroNode(8,"李宗盛 new","鬼才 new"));
////        System.out.println("打印");
////        singleLinkedList.show();
//        singleLinkedList.delete(2);
//        singleLinkedList.delete(8);
//        System.out.println("删除后");
//        singleLinkedList.show();

        //求单链表节点个数
//        System.out.println("节点个数:"+singleLinkedList.getNodeSize());
//        System.out.println("倒数第二个节点:"+singleLinkedList.findLastIndexNode(2));

//        System.out.println("反转");
//        singleLinkedList.reversetList();
//        singleLinkedList.show();

        singleLinkedList.reverPrint();


    }
}

//定义一个SingleLinkedList
class SingleLinkedList{
    //先定义一个头结点
    private HeroNode header=new HeroNode(0,"","");

    //添加到最后
    public void addTail(HeroNode node){
        //从头结点开始,找到最后一个节点(next=null)
        HeroNode temp=header;
        while(true){
            if(temp.next==null){
                break;
            }
            //后移
            temp=temp.next;
        }
        //跳出循环说明找到最后一个元素
        temp.next=node;
    }

    //根据no进行添加 不能重复添加
    public void addByOrder(HeroNode node){
        //从头节点开始
        HeroNode temp=header;
        while (true){
            if(temp.next==null){
                break;
            }
            //需找到添加位置的前一个节点
            if(node.no<temp.next.no){
                break;
            }
            if(node.no==temp.next.no){
                throw new RuntimeException("【"+node.no+"】已经存在");
            }
            temp=temp.next;
        }
        //此时符合添加条件
        HeroNode heroNode=temp.next;
        temp.next=node;
        node.next=heroNode;
    }

    //根据no进行修改
    public void update(HeroNode node){
        if(header.next==null){
            throw new RuntimeException("链表为空");
        }
        boolean update=false;
        HeroNode temp=header.next;
        while (true){
            if(temp==null){
                break;
            }
            if(temp.no==node.no){
                update=true;
                temp.name=node.name;
                temp.nickName=node.nickName;
                break;
            }
            temp=temp.next;
        }
        if(!update){
            System.out.println("更新失败,没有找到【"+node.no+"】元素");
        }
    }

    //根据no进行删除
    public void delete(int no){
        HeroNode temp=header;
        boolean delete=false;

        while (true){
            if(temp.next==null){
                break;
            }
            //找到这个元素前一个节点
            if(temp.next.no==no){
                delete=true;
                temp.next=temp.next.next;
                break;
            }
            temp=temp.next;
        }
        if(!delete){
            throw new RuntimeException("删除失败,没有找到【"+no+"】元素");
        }
    }

    //显示链表
    public void show(){
        if(header.next==null){
            System.out.println("链表为空");
            return;
        }
        //从头结点开始
        HeroNode temp=header;
        while (true){
            if (temp.next!=null){
                System.out.println(temp.next);
                temp=temp.next;
            }else {
                break;
            }
        }
    }

    //单链表节点个数
    public int getNodeSize(){
        HeroNode temp=header.next;
        int count=0;
        while (true){
            if(temp==null){
                break;
            }
            count++;
            temp=temp.next;
        }
        return count;
    }

    //查找单链表倒数第K个节点 得到size 遍历到size-index即可
    public HeroNode findLastIndexNode(int index){
        int size=getNodeSize();
        if(index<=0||index>size){
            throw new RuntimeException("索引不符合规则");
        }
        int n=size-index; //逆序转正序
        int count=0;
        HeroNode temp=header.next;

        while (true){
            if(temp==null){
                break;
            }
            if(count==n){
                break;
            }
            temp=temp.next;
            count++;
        }
        return temp;
    }

    //将单链表实现反转
    public void reversetList(){
        //没有或者只有一个节点
        if(header.next==null||header.next.next==null){
            return ;
        }
        //新建一个反转节点
        HeroNode reverHeader = new HeroNode(-1, "", "");
        HeroNode cur=header.next;
        HeroNode next=null;
        //遍历原来的节点
        while (true){
            if(cur==null){
                break;
            }
            //每遍历一个节点就放入reverHeader的最前端 把之前那个元素指向当前下一个
            next=cur.next;
            cur.next=reverHeader.next;//每次指向最前一个
            reverHeader.next=cur;
            //继续遍历
            cur=next;
        }
        //最后将header指向reverheader.next
        header.next=reverHeader.next;
    }

    public void reverPrint(){
        if(header.next==null){
            return;
        }
        HeroNode temp=header.next;
        Stack<HeroNode> stack=new Stack<HeroNode>();
        while (true){
            if(temp==null){
                break;
            }
            stack.push(temp);
            temp=temp.next;
        }
        System.out.println("----反向输出---");
        while (stack.size()>0){
            System.out.println(stack.pop());
        }

    }
}

//定义一个英雄节点
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;
    }

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

双向链表

单向链表的缺点分析:

单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。

单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点。

public class DoubleLinkedListDemo {

    public static void main(String[] args) {
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.add(new HeroNode2(1,"张三","zs"));
        doubleLinkedList.add(new HeroNode2(2,"李四","ls"));
        doubleLinkedList.add(new HeroNode2(3,"王五","ww"));
        doubleLinkedList.add(new HeroNode2(4,"赵六","zl"));
        doubleLinkedList.add(new HeroNode2(5,"宋七","sq"));
        doubleLinkedList.display();

////        doubleLinkedList.delete(1);
//
//        doubleLinkedList.update(new HeroNode2(5,"宋七 new","sq new"));
//
//        doubleLinkedList.delete(8);

        doubleLinkedList.add(2,new HeroNode2(7,"宋七1","sq1") );

        doubleLinkedList.display();
    }
}

class DoubleLinkedList{
    HeroNode2 header=new HeroNode2(0,"","");

    //返回头节点
    public HeroNode2 getHeader(){
        return header;
    }

    //遍历
    public void display(){
        System.out.println("-------显示-------");
        HeroNode2 cur=header.next;
        if(cur==null){
            System.out.println("链表为空");
        }
        while (true){
            if(cur==null){
                break;
            }
            System.out.println(cur);
            cur=cur.next;
        }
    }

    //添加
    public void add(HeroNode2 node){
        HeroNode2 cur=header;
        //找到最后一个元素加上
        while (true){
            if(cur.next==null){
                break;
            }
            cur=cur.next;
        }
        cur.next=node;
        node.pre=cur;
    }

    //根据no 添加
    public void add(int no,HeroNode2 node){
        HeroNode2 cur=header.next;
        int count=1;
        //找到最后一个元素加上
        while (true){
            if(count==no){
                break;
            }
            count++;
            cur=cur.next;
        }
        cur.pre.next=node;
        node.next=cur;
        node.pre=cur.pre;
        cur.pre=node;
    }

    //根据no进行修改
    public void update(HeroNode2 node){
        if(header.next==null){
            throw new RuntimeException("链表为空");
        }
        boolean update=false;
        HeroNode2 temp=header.next;
        while (true){
            if(temp==null){
                break;
            }
            if(temp.no==node.no){
                update=true;
                temp.name=node.name;
                temp.nickName=node.nickName;
                break;
            }
            temp=temp.next;
        }
        if(!update){
            System.out.println("更新失败,没有找到【"+node.no+"】元素");
        }
    }


    //根据no删除一个节点
    public void delete(int no){
        if(header.next==null){
            throw new RuntimeException("链表为空");
        }
        boolean delete=false;
        HeroNode2 temp=header.next;
        while (true){
            if(temp==null){
                break;
            }
            if(temp.no==no){
                //删除就是改变指向
                temp.pre.next=temp.next;
                //如果最后一个节点不需要执行
                if(temp.next!=null){
                    temp.next.pre=temp.pre;
                }
                delete=true;
                break;
            }
            temp=temp.next;
        }
        if(!delete){
            System.out.println("删除失败,没有找到【"+no+"】元素");
        }
    }
}


//定义一个节点
class HeroNode2 {
    public int no;
    public String name;
    public String nickName;
    public HeroNode2 pre;
    public HeroNode2 next;

    public HeroNode2(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

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