(二)链表

一 定义

链表是有序的列表,但是它在内存中是存储如下:

image.png

小结:

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

逻辑结构

image.png

二 单向链表-水浒英雄排名

需求

使用带head头单向链表实现 –水浒英雄排行榜管理

  1. 完成对英雄人物的增删改查操作
  2. 第一种方法在添加英雄时,直接添加到链表的尾部
  3. 第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

head头

  • 不存放具体的数据
  • 指向第一个节点

思路分析

  1. 添加到末尾没什么好说的
  2. 按排名顺序添加。我们在添加时队列就是升序的,我们只要找到第一个比当前插入节点大的节点,插到它前面即可

代码

链表

public class SingleLinkedList {

    private HeroNode head = new HeroNode();//头节点,指向第一个节点

    private HeroNode last = null;//尾节点,就是最后一个节点

    private int length;

    /**
     * 增加到最后
     * @param node
     */
    public void add(HeroNode node){
        if(head.getNext() ==null){
            head.setNext(node);
            last = node;
        }else{
            last.setNext(node);
            last = node;
        }
    }

    public void show(){
        HeroNode next = head.getNext();
        while(next != null){
            System.out.println(next);
            next = next.getNext();
        }
    }

    public void addByNoAsc(HeroNode node){
        if(head.getNext() ==null){
            head.setNext(node);
            last = node;
        }else{
            HeroNode preNode = head;//头元素
            HeroNode next = head.getNext();//第一个元素
            while(next != null){
                if(next.getNo() == node.getNo()){
                    throw new RuntimeException("no异常");
                }else if(next.getNo() > node.getNo()){
                    //结束,插前面
                    node.setNext(next);
                    preNode.setNext(node);
                    return;
                }else{

                    //继续往下找
                    preNode = next;
                    next = next.getNext();
                    continue;
                }

            }
            //上面遍历完了还没找到比当前节点大的,就插入到最后
            last.setNext(node);
            last = node;
        }
    }



}

节点

class HeroNode{

    private String name;

    private String nickname;

    private int no;

    private HeroNode next;

    public HeroNode() {
    }

    public HeroNode(int no, String name, String nickname) {
        this.name = name;
        this.nickname = nickname;
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public HeroNode getNext() {
        return next;
    }

    public void setNext(HeroNode next) {
        this.next = next;
    }

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

测试

    @Test
    public void testSingleLinkedList1(){

        HeroNode node1 = new HeroNode(1,"宋江","呼保义");
        HeroNode node7 = new HeroNode(7,"秦明"," 霹雳火");
        HeroNode node4 = new HeroNode(4,"公孙胜","入云龙");
        HeroNode node3 = new HeroNode(3,"吴用","智多星");
        HeroNode node2 = new HeroNode(2,"卢俊义"," 玉麒麟");
        HeroNode node5 = new HeroNode(5,"关胜"," 大刀");
        HeroNode node6 = new HeroNode(6,"林冲"," 豹子头");

        HeroNode node8 = new HeroNode(8,"呼延灼"," 双鞭");


        SingleLinkedList list = new SingleLinkedList();
        list.addByNoAsc(node1);
        list.add(node7);
        list.addByNoAsc(node5);
        list.addByNoAsc(node2);
        list.addByNoAsc(node3);
        list.add(node8);
        list.addByNoAsc(node6);
        list.addByNoAsc(node4);

        list.show();
    }

单链表反转

反转就是遍历原始链表时采用头插法

    public void reverse(){
        if(last == null){
            return;
        }
        HeroNode newHead = new HeroNode();
        HeroNode oldFirstHead;
        HeroNode next;
        /*
        开始遍历
         */
        HeroNode cur = head.getNext();//第一个元素
        while(cur != null){
            next = cur.getNext();
            if(newHead.getNext()==null){
                newHead.setNext(cur);
                last = cur;
                cur.setNext(null);
            }else{
                oldFirstHead = newHead.getNext();///指向原来的第一个元素
                newHead.setNext(cur);
                cur.setNext(oldFirstHead);
            }
            cur = next;
        }


        head = newHead;
    }

合并两个有序的单链表

可以直接调用addByNoAsc的:缺点每次都从头开始比(其实前面比过的已经不需要再比了).所以新写了方法

代码

    public HeroNode get(){
        if(head.getNext() == null){
            return null;
        }else{
            HeroNode temp = head.getNext();
            head.setNext(temp.getNext());
            temp.setNext(null);
            return  temp;
        }
    }

    /**
     * 有序合并
     * @param list
     */
    public void mergeByAsc(SingleLinkedList list){
        HeroNode node = list.get();

        HeroNode cur = head.getNext();
        HeroNode pre = head;
        while(node != null){
            /**
             * 一样的道理
             * 在原始链表中找到比自己大的
             * 直接调用addByNoAsc的:缺点每次都从头开始比
             */
            if(cur == null){
                if(head.getNext() == null){
                    head.setNext(node);
                }else{
                    last.setNext(node);//先指向
                }
                /**
                 * 结束了,后面都好了(因为node已经清掉了next,所以还需要处理)
                 */

                last = node;//后调整last
                node = list.get();
            }else{

                while(cur != null){
                    if(cur.getNo() >= node.getNo()){//找到位置
                        pre.setNext(node);
                        node.setNext(cur);
                        pre= node;
                        node = list.get();

                        break;//下一个node
                    }else{//继续找
                        pre = cur;
                        cur = cur.getNext();
                    }

                }
                //找完了

            }

        }

    }

测试

    @Test
    public void testSingleLinkedList1(){

        HeroNode node1 = new HeroNode(1,"宋江","呼保义");
        HeroNode node11 = new HeroNode(1,"宋江","呼保义(神)");
        HeroNode node7 = new HeroNode(7,"秦明"," 霹雳火");
        HeroNode node4 = new HeroNode(4,"公孙胜","入云龙");
        HeroNode node3 = new HeroNode(3,"吴用","智多星");
        HeroNode node31 = new HeroNode(3,"吴用","智多星(神)");
        HeroNode node2 = new HeroNode(2,"卢俊义"," 玉麒麟");
        HeroNode node5 = new HeroNode(5,"关胜"," 大刀");
        HeroNode node6 = new HeroNode(6,"林冲"," 豹子头");

        HeroNode node8 = new HeroNode(8,"呼延灼"," 双鞭");
        HeroNode node9 = new HeroNode(9,"花荣"," 小李广");


        SingleLinkedList list = new SingleLinkedList();
        SingleLinkedList list2 = new SingleLinkedList();

//        list.addByNoAsc(node1);
//        list.addByNoAsc(node7);
//        list.addByNoAsc(node5);
//        list.addByNoAsc(node3);

        list2.addByNoAsc(node8);
        list2.addByNoAsc(node2);
        list2.addByNoAsc(node6);
        list2.addByNoAsc(node4);
        list2.addByNoAsc(node31);
        list2.addByNoAsc(node11);
        list2.addByNoAsc(node9);



        list.show();
        System.out.println("---------");
        list2.show();
        System.out.println("---------");
        list.mergeByAsc(list2);


        list.show();
    }

三 双向链表

  • 单向链表,查找的方向只能是一个方向,而双向链�表可以向前或者向后查找。
  • 单向链表不能自我删除,需要靠辅助节点 ,而双向�链表,则可以自我删除,所以前面我们单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点
image.png

本质没上面区别,就不行写了,只是加了个pre属性。指向前一个元素

四 单向环形链表(约瑟夫)

Josephu 问题为: 设编号为 1, 2, … n 的 n 个人围坐一圈, 约定编号为 k(1<=k<=n) 的人从 1 开始报数, 数
m的那个人出列, 它的下一位又从 1开始报数, 数到 m 的那个人又出列, 依次类推, 直到所有人出列为止, 由
此产生一个出队编号的序列

思路分析

用一个不带头结点循环链表来处理 Josephu 问题: 先构成一个有 n 个结点的单循环链表, 然后由k 结 点起从 1 开始计数, 计到m 时, 对应结点从链表中删除, 然后再从被删除结点的下一个结点又从 1 开始计数, 直
到最后一个结点从链表中删除算法结束。

代码实现

    public void sequence(int n,int k,int m){
        //TODO: 参数校验省略...
        Node first = null;//
        Node head = null;//初始化时,指向node1
        Node pre = null;//前一次初始化的节点
        //初始化
        for(int i= 1;i<=n;i++){
            Node node = new Node(i);
            if(i == 1){
                head = node;
                pre = node;
            }else if(i == n){
                pre.setNext(node);
                node.setPre(pre);
                node.setNext(head);
                head.setPre(node);
            }else{
                pre.setNext(node);
                node.setPre(pre);
                pre = node;
            }
            if(i == k){
                first = node;
            }
        }

        /**
         * 开始依次出队
         */
        int index = 1;
        while(first != null){
            if(index == m){
                //出队
                System.out.println(first);
                Node preNode = first.getPre();
                if(preNode == first)//自己连自己
                    return;//最后一个元素了,结束了

                first = first.getNext();

                preNode.setNext(first);
                first.setPre(preNode);
                index = 1;//重置

            }else{
                first = first.getNext();
                index++;
            }

        }


    }

测试

    @Test
    public void test(){
        sequence(5,2,3);

    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容