3 单链表

文章目录

  • 1 介绍
  • 2 单链表
  • 3 实例
  • 4 总结

1 介绍

链表是有序的列表,但是它在内存中是存储如下
3 单链表_第1张图片
链表是以节点的方式来存储,是链式存储
每个节点包含 data 域, next 域:指向下一个节点.
如图:发现链表的各个节点不一定是连续存储.
链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定

2 单链表

3 单链表_第2张图片
单链表就是单向链表,从head开始指向下一个节点,指向的方向是单向的.

3 实例

使用带head头的单向链表实现 –水浒英雄排行榜管理
完成对英雄人物的增删改查操作
第一种方法在添加英雄时,直接添加到链表的尾部
第二种方式在添加英雄时,根据排名将英雄插入到指定位置

代码实现:

package LinkList;

import java.util.Stack;

public class SingleLinkListDemo {
    public static void main(String[] args) {
        HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
        HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
        HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");

        SingleLinkList list = new SingleLinkList();

        // list.add(hero1);
        // list.add(hero3);
        // list.add(hero2);
        // list.add(hero4);

        list.addByOrder(hero1);
        list.addByOrder(hero3);
        list.addByOrder(hero2);
        list.addByOrder(hero4);

        // list.del(2);

        // HeroNode herotemp = new HeroNode(3, "andy", "帅哥");
        //
        // list.update(herotemp);
        // System.out.println(list.getLength());

        //System.out.println(list.findLastIndexNode(1));
        //list.reversetList();

        list.reversePrint();

    }
}


class SingleLinkList{
    private HeroNode head = new HeroNode(0,"","");

    /**
     * 逆序打印链表
     * 利用栈先进后出的特点,把链表从头到尾压栈
     * 出栈的时候就是从尾到头
     */
    public void reversePrint(){
        //空表
        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());
        }
    }

    /**
     * 链表翻转
     */
    public void reversetList(){
        //如果链表为空或者是链表只有一个元素无需翻转
        if (head.next == null || head.next.next == null)
            return;

        HeroNode tempHead = head.next;
        HeroNode temp;
        head.next = null;

        while (tempHead != null){
            temp = tempHead.next;
            tempHead.next = head.next;
            head.next = tempHead;
            tempHead = temp;
        }


    }

    /**
     * 求出链表中倒数最后的第几个元素
     * 思路:
     * 先求出整个链表的长度length
     * 然后用length-lastindex就得到第几个倒数元素的正序值
     * 然后在遍历链表找到该元素,返回
     * @param lastIndex
     * @return
     */
    public HeroNode findLastIndexNode(int lastIndex){
        if (head.next == null)
            return null;
        int length = getLength();
        if (lastIndex < 0 || lastIndex > length)
            return null;
        HeroNode temp = head.next;
        for (int i = 0;i < length - lastIndex;i++)
            temp = temp.next;
        return temp;
    }

    /**
     * 获取头结点
     * @return
     */
    public HeroNode getHead(){
        return head;
    }

    /**
     * 返回有效节点的数量(链表的大小,不包括头结点)
     */
    public  int getLength(){

        HeroNode temp = head.next;
        int length = 0;

        while(temp != null){
            length ++;
            temp = temp.next;
        }
        return length;
    }

    /**
     * 删除
     * @param no
     */
    public void del(int no){

        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }

        HeroNode temp = head;
        boolean flag = false; //找到节点的标标志

        while (temp.next != null){
            if (temp.next.no == no){
                flag = true;
                break;
            }
            temp = temp.next;
        }

        if (flag){
            temp.next = temp.next.next;
        }else{
            System.out.printf("没有找到编号%d的节点,不能删除\n",no);
        }

    }


    /**
     * 更新节点的数据
     * @param heroNode
     */
    public void update(HeroNode heroNode){
        //链表为空
        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }

        HeroNode temp = head.next;
        boolean flag = false; //找到节点的标标志

        while (temp != null){
            if (temp.no == heroNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }

        if (flag){
            temp.name = heroNode.name;
            temp.nickname = heroNode.nickname;
        }else{
            System.out.printf("没有找到编号%d的节点,不能修改\n",heroNode.no);
        }

    }


    /**
     * 在链表的尾部添加一个节点
     * @param heroNode
     */
    public void add(HeroNode heroNode){
        HeroNode temp = head; //temp用来遍历列表找到链表的尾部

        while(temp.next != null){
            temp = temp.next;
        }

        //在链表的尾部插入节点
        temp.next = heroNode;
    }

    /**
     * 按照排名插入hero
     * @param heroNode
     */

    public void addByOrder(HeroNode heroNode){
        HeroNode temp = head;
        boolean flag = false;

        while (temp.next != null){
            if(temp.next.no > heroNode.no){ //找到位置
                break;
            }else if (temp.next.no == heroNode.no){//编号已经存在
                flag = true;
                break;
            }

            temp = temp.next;
        }

        if(flag){
            System.out.printf("准备插入的英雄的编号%d已经存在,不能加入\n",heroNode.no);
        }else{//进行插入,注意,如果到达链表的尾部还没找到,就在尾部插入
            heroNode.next = temp.next;
            temp.next = heroNode;
        }

    }

    /**
     * 打印链表
     */

    public void show(){
        //链表为空
        if (head.next == null){
            System.out.println("链表为空!");
            return;
        }

        HeroNode temp = head.next;

        while (temp != null){
            System.out.println(temp);
            temp = temp.next;
        }
    }
}



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.nickname = nickname;
        this.name = name;
    }

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

4 总结

上面的实例是很简单的.
一般的链表都会有在指定位置插入一个节点等操作,但上面的例子没有实现.
相比较于数组,链表的优势在于添加和删除和空间的利用率,而缺点是随机访问.
如果有频繁添加的操作可以使用链表,而频繁读取数据的使用数组.

你可能感兴趣的:(数据结构与算法)