首页 > 编程语言 > 详细

D2-链表[Java数据结构和算法]

时间:2019-07-23 15:51:17      阅读:67      评论:0      收藏:0      [点我收藏+]

1.单链表的介绍和内存布局

  1.1链表是有序的列表,以节点的方式进行存储,每个节点包含data域,next域;

  (1)data域:存储数据;next域:指向下一个节点

  1.2 链表的各个节点不一定是连续存储的

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

2.单链表的具体实现

  2.1在添加英雄时,直接添加到链表的尾部

  (1)分析

    -先创建一个head头节点,作用就是表示单链表的头

    -每添加一个节点,就直接加入到链表的最后

    -遍历:通过辅助遍历遍历,帮助遍历整个链表

  (2)源代码

package cn.atguigu.Linkedlist;

public class SingleLinkedlistDemo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SingleLinkedlist singlelinkedlist=new SingleLinkedlist();
        
        HeroNode hero1=new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2=new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3=new HeroNode(3, "吴用", "智多星");
        HeroNode hero4=new HeroNode(4, "林冲", "豹子头");
        
        singlelinkedlist.add(hero1);
        singlelinkedlist.add(hero2);
        singlelinkedlist.add(hero3);
        singlelinkedlist.add(hero4);
        
        singlelinkedlist.show();
    }
    
//创建SingleLinkedlist类
public static class SingleLinkedlist{
    //创建头节点
    private HeroNode head=new HeroNode(0, "", "");
    //实现英雄人物的添加
    public void add(HeroNode HeroNode) {
        //创建临时节点指向head
        HeroNode temp=head;
        //寻找最后一个节点
        while(true) {
            if(temp.next==null) {//如果临时节点的下一个域为空,则其为最后一个节点
                break;
            }else {//否则临时节点后移
                temp=temp.next;
            }
        }//temp指向最后一个节点,将新节点添加到temp.next
        temp.next=HeroNode;        
    }
    //实现显示链表
    public void show() {
        //创建临时节点指向head
        HeroNode temp=head;
        //判断链表是否为空
        if(temp.next==null) {
            System.out.println("链表为空");
            return;
        }
        while(true) {
            if(temp.next==null) {//若临时变量的next为null,跳出循环
                break;
            }else {
                temp=temp.next;
                System.out.println(temp);
            }
        }
    }
}

//创建HeroNode类
public static 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;
    }
    
    //为方便显示,重写toString方法
    @Override
    public String toString() {
        return "HeroNode no=" + no + ", name=" + name + ", nickname=" + nickname;
    }
}
}

 

  2.2 在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,给出提示)

  (1)分析

    -首先找到新添加的节点的位置,是通过辅助变量遍历解决

    -新的节点.next=temp.next

    -将temp.next=新的节点

  (2)源代码-添加到SingleLinkedlist类

public void addByOrder(HeroNode HeroNode) {
        //创建临时节点
        HeroNode temp=head;
        //创建布尔变量,判断链表中是否存在该排名的英雄,若有为true,其默认值为false
        boolean flag=false;
        while(true) {
            //判断链表是否为空
            if (temp.next==null) {
                break;
            }
            if(temp.next.no>HeroNode.no) {//如果临时节点下一节点的排名大于新节点的排名,则该新节点应当添加在新节点后
                break;
            }else if(temp.next.no==HeroNode.no){//说明该排名的英雄已存在,不需要添加
                flag=true;    
            }
            temp=temp.next;//temp后移
        }
        //判断flag
        if(flag) {
            System.out.println(temp+"已存在,不需添加");
        }else {
            HeroNode.next=temp.next;
            temp.next=HeroNode;
        }
    }

 

  2.3 修改名字和昵称

//修改节点的信息,根据no编号来修改
    public void update(HeroNode heroNode) {
        //判断节点是否为空
        if(head.next==null) {
            System.out.println("链表为空,无法修改");
        }
        //创建临时节点
        HeroNode temp=head;
        //创建布尔值,默认为false,找到该排名时设置为true
        boolean flag=false;
        while(true) {
            if(temp.next==null) {
                break;
            }
            if(temp.no==heroNode.no) {
                flag=true;
                break;
            }
            temp=temp.next;
        }
        //判断flag
        if(flag) {
            temp.name=heroNode.name;
            temp.nickname=heroNode.nickname;
        }else {
            System.out.println("没有找到"+heroNode.no+"的节点");
        }
    }

 

  2.4 实现节点的删除

  (1)分析

    -先找到需要删除节点的前一个节点temp

    -temp.next=temp.next.next

    -被删除的节点,将不会有其他引用指向,会被垃圾回收机制回收

//实现节点的删除,根据no编号删除
    public void delete(HeroNode heroNode) {
        //判断节点是否为空
        if(head.next==null) {
            System.out.println("链表为空,无法删除");
        }
        //创建临时节点
        HeroNode temp=head;
        //创建布尔值,默认为false,找到该排名时设置为true
        boolean flag=false;
        while(true) {
            if(temp.next==null) {
                break;
            }else if(temp.next.no==heroNode.no) {//若临时节点下一节点的no编号与待删除的编号相同,设置flag变量,跳出循环
                flag=true;
                break;
            }
            temp=temp.next;
        }
        //根据flag判断
        if(flag) {
            temp.next=temp.next.next;
        }else {
            System.out.println("没有找到"+heroNode.no+"的节点");
        }
    }

 

  2.5 单链表面试题

//查找单链表中的倒数第k个节点【新浪面试题】
    //思路
    //1编写一个方法,接收head节点,同时接受一个index
    //2index表示是倒数第k个节点
    //3先把链表从头到尾遍历,得到链表的总长度getLength
    //4得到size后,从链表的第一个开始遍历(size-index)个
    public static HeroNode findLastIndexNode(HeroNode head,int index) {
        //判断链表是否为空
        if(head.next==null) {
            return null;//没有找到
        }
        int k=0;
        if(0<=index&&index<=getLength(head)) {
            k=getLength(head)-index;            
        }else {
            return null;
        }
        HeroNode temp=head.next;
        for(;k>0;k--) {
            temp=temp.next;
        }
        return temp;            
    }
    //方法:实现单链表的逆序打印[百度面试]
    //方式1:先将单链表进行反转操作,然后再遍历即可,存在问题是会破坏原来的单链表的结构,不建议
    //方式2:利用栈的数据结构,将各个节点压入到栈中,利用栈先进后出的特点实现逆序打印,使用stack集合
    public static void reversePrint(HeroNode head) {
        if(head.next==null) {
            return;//空链表,不能打印
        }
        //创建一个栈
        Stack<HeroNode> stack=new Stack<HeroNode>();
        HeroNode temp=head.next;
        //入栈
        while(temp!=null) {
            stack.push(temp);
            temp=temp.next;
        }
        while(stack.size()>0) {
            System.out.println(stack.pop());
        }
    }
    //方法:实现单链表的反转【腾讯面试】
    /*
     * 思路:
     * 1.先定义一个节点reverseHead=new HeroNode();
     * 2.从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表的最前端
     * 3.原来的链表head.next=reverseHead.next
     */
    public static void reverse(HeroNode head) {
        //创建新的头节点
        HeroNode reverseHead =new HeroNode(0,"","");
        //判断链表是否为空,或只有一个节点,无需反转
        if(head.next==null||head.next.next==null) {
            return;
        }
        //遍历链表
        //创建辅助指针,帮助遍历原来的链表
        HeroNode temp=head.next;
        HeroNode next=null;//指向当前节点temp的下一个节点
        while(temp!=null) {
            next=temp.next;//保存当前节点的下一个节点
            temp.next=reverseHead.next;//将temp的下一个节点指向新的链表的最前端
            reverseHead.next=temp;
            temp=next;//temp后移
        }
        head.next=reverseHead.next;
    }
    
    //方法:获取到单链表的节点的个数(如果是带头结点的链表,要求不统计头节点)
    /**
     * @param head 链表的头节点
     * @return 返回的是有效节点的个数
     * @author motke
     *
     */
    public static int getLength(HeroNode head) {
        HeroNode temp=head;
        int num=0;
        if(head.next==null) {//空链表
            return 0;
        }
        while(temp.next!=null) {
            num++;
            temp=temp.next;        
        }
        return num;            
    }
    

   2.6 单链表的缺点分析

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

  (2)单向链表不能自我删除,需要依靠辅助节点,双向链表可以实现自我删除。

 

3.双链表的具体实现

package cn.atguigu.Linkedlist;


public class DoubleLinkedlistDemo {
    public static void main(String[] args) {
        DoubleLinkedlist doubleLinkedlist=new DoubleLinkedlist();
        HeroNode hero1=new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2=new HeroNode(2, "林冲", "豹子头");
        HeroNode hero3=new HeroNode(3, "卢俊义", "玉麒麟");
        HeroNode hero4=new HeroNode(4, "吴用", "智多星");
        HeroNode hero5=new HeroNode(4, "史进", "九纹龙");
        //实现双链表的添加
        doubleLinkedlist.add(hero1);
        doubleLinkedlist.add(hero2);
        doubleLinkedlist.add(hero3);
        doubleLinkedlist.add(hero4);
        System.out.println("添加的效果~~");
        doubleLinkedlist.show();
        
        //实现双链表的修改
        System.out.println("修改后的效果~~");
        doubleLinkedlist.update(hero5);
        doubleLinkedlist.show();
        
        //实现双链表的删除
        System.out.println("删除后的效果~~");
        doubleLinkedlist.delete(4);
        doubleLinkedlist.show();
        
    }
    
    public static class HeroNode {//创建双向链表的节点
        public int no;
        public String name;
        public String nickname;
        public HeroNode next;
        public HeroNode pre;//指向前一个节点
        //构造器
        public HeroNode(int no, String name, String nickname) {
            this.no = no;
            this.name = name;
            this.nickname = nickname;
        }
        //修改toString
        @Override
        public String toString() {
            return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
        }
    }
    
    public static class DoubleLinkedlist{
        //创建头节点
        HeroNode head=new HeroNode(0, "", "");
        //实现新节点的添加操作
        public void add(HeroNode heroNode) {
            //创建临时节点
            HeroNode temp=head;
            //temp.pre=head;
            //找到该链表的最后一个节点
            while(temp.next!=null) {
                temp=temp.next;
            }
            //实现新节点的添加
            temp.next=heroNode;
            heroNode.pre=temp;
        }
        public void delete(int no) {
            //判断节点是否为空
            if(head.next==null) {
                System.out.println("链表为空,无法修改");
                return;
            }
            //创建临时节点
            HeroNode temp=head.next;
            //创建布尔值,默认为false,找到该排名时设置为true
            boolean flag=false;
            while(true) {
                if(temp==null) {
                    break;
                }else if(temp.no==no) {//若临时节点下一节点的no编号与待删除的编号相同,设置flag变量,跳出循环
                    flag=true;
                    break;
                }
                temp=temp.next;
            }
            //根据flag判断
            if(flag) {
                temp.pre.next=temp.next;
                if(temp.next!=null) {
                    temp.next.pre=temp.pre;                    
                }
            }else {
                System.out.println("没有找到"+no+"的节点");
            }
        }
        
        //修改节点的信息,根据no编号来修改
        public void update(HeroNode heroNode) {
            //判断节点是否为空
            if(head.next==null) {
                System.out.println("链表为空,无法修改");
                return;
            }
            //创建临时节点
            HeroNode temp=head;
            //创建布尔值,默认为false,找到该排名时设置为true
            boolean flag=false;
            while(true) {
                if(temp==null) {
                    break;
                }
                if(temp.no==heroNode.no) {
                    flag=true;
                    break;
                }
                temp=temp.next;
            }
            //判断flag
            if(flag) {
                temp.name=heroNode.name;
                temp.nickname=heroNode.nickname;
            }else {
                System.out.println("没有找到"+heroNode.no+"的节点");
            }
        }
        
        //实现显示链表
        public void show() {
            //创建临时节点指向head
            HeroNode temp=head;
            //判断链表是否为空
            if(temp.next==null) {
                System.out.println("链表为空");
                return;
            }
            while(true) {
                if(temp.next==null) {//若临时变量的next为null,跳出循环
                    break;
                }else {
                    temp=temp.next;
                    System.out.println(temp);
                }
            }
        }
    }
}

 

 

4. 环形链表介绍和约瑟夫问题

  4.1 环形链表的应用场景-约瑟夫问题(Josephu)

  设编号为1,2,3...,n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又开始从1开始报数,数到m的那个人再出列,以此类推,直到所有人出列为止,由此产生一个出队变好的序列。

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

  4.2 源代码实现

 

D2-链表[Java数据结构和算法]

原文:https://www.cnblogs.com/ERFishing/p/11221433.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!