集合----链式存储的实现

一 、链表的概念

集合的顺序存储是通过数组来实现的,集合的链式存储是通过存储结点之间的链接来实现的,从而形成链表。链表中的每一个结点都包含一个值域和一个指针(即引用对象域),每个结点的指针指向下一个结点对象,这样的链表称之为单链表。在单链表中,第一个结点称之为表头结点,指向第一个结点的指针被称为表头指针,最后一个结点称为表尾结点,表尾结点的指针为空。通常,为了方便插入和删除结点,通常在表头结点增加一个无值的结点,我们称之为附加头结点,用head表示,如链表为空,附加头结点的指针域指向自身,指针域为空,若链表不为空,则附加头结点的指针指向第一个结点。如下图所示。


这里写图片描述


二 、结点类的定义

我们定义类名为Node,数值域和指针域分别用element和next表示。该类包括两个构造方法,一个只带有结点引用对象参数,实现对当前next结点的赋值;另一个带有两个参数,分别实现对当前结点的值域element和指针域next的赋值。Node结点的定义如下:

public class Node {
    Object element;
    Node next;
    public Node(Node next){
        this.next = next;
    }
    public Node(Object element,Node next){
        this.element = element;
        this.next = next;
    }

}

三 、具体操作的实现

1 、初始化集合,首先我们要定义附加头结点head为null和链表的长度length为0,然后再定义一个无参构造方法。

public class LinkedSet {
    public Node head;
    public int length;
    public LinkedSet(){

        head = new Node(null);
        length = 0;

    }
}

2 、向集合中添加一个元素

    public boolean add(Object obj){
        Node temp = head;       //定义一个Node类型的临时变量,指向附加头结点
        while(temp.next!=null){     //是否为链表最后的结点

            if(temp.next.element.equals(obj)){  //判断链表中是否有与obj内容相同的结点

                return false;

            }else{

                temp = temp.next;   //如果不是,则取下一个结点
            }
        }
        temp.next = new Node(obj,null); //temp为链表的最后一个结点,并在该结点后创建一个新的结点
        length++;           //链表的长度加1
        return true;
    }

3 、从集合中删除一个元素

    public boolean remove(Object obj){
        Node temp = head;       //定义一个Node类型的临时变量,指向附加头结点
        while(temp.next!=null){     //循环遍历单链表
            if(temp.next.element.equals(obj)){      //判断是否存在相同的元素,若存在,则跳出循环
                break;
            }
            temp = temp.next;           //修改temp,指向后继结点
        }
        if(temp.next!=null){        //条件成立时,temp.next指要删除的结点
            temp.next = temp.next.next;     //从链表中删除该结点
            length--;                       //链表长度减1
            return true;                    //删除成功返回true
        }
        return false;                       //删除失败返回false
    }

4 、判断一个元素是否属于该集合

    public boolean contains(Object obj){
        Node temp = head.next;      //定义一个Node类型的临时变量,指向第一个结点
        while(temp!=null){      //循环遍历单链表
            if(temp.element.equals(obj)){   //判断是否存在相同的元素,若存在,则返回true
                return true;
            }
            temp = temp.next;       //修改temp,指向后继结点
        }
        return false;               //若不存在,则返回false
    }

5 、返回集合中第i个元素的值

    public Object get(int index){
        if(index<1||index>length){
            System.out.println("该索引不在集合范围内");
            System.exit(1);     //结束该方法
        }
        Node temp = head;       //定义一个Node类型的临时变量,指向附加头结点
        int i = 1;              
        while(i<=index){        //定义一个变量,用来表示循环的次数
            temp = temp.next;   //修改temp,指向后继结点
            i++;                //i自动加1
        }
        return temp.element;    //返回查找结点的内容
    }

6 、从集合中按值查找元素

    public Object find(Object obj){
        Node temp = head.next;      //定义一个Node类型的临时变量,指向第一个结点
        while(temp!=null){          //循环遍历单链表
            if(temp.element.equals(obj)){       //判断是否存在相同的元素,若存在,则返回obj
                return obj;
            }
            temp = temp.next;           //修改temp,指向后继结点
        }
        return null;                    //查找失败返回null
    }

7 、返回集合的长度

public int size(){
        return length;
    }

8 、判断集合是否为空

public boolean isEmpty(){
        return length==0;
    }

9 、输出集合的所有元素

public void print(){
        Node temp = head.next;
        while(temp!=null){
            System.out.print(temp.element.toString()+" ");
        }
        System.out.println();
    }

10 、求两个集合的并集

public LinkedSet union(LinkedSet set){
        LinkedSet setTemp = new LinkedSet();    //定义一个新的链表,用来存放两个集合的并集
        //setTemp添加当前集合的元素
        Node temp = head.next;
        while(temp!=null){
            setTemp.add(temp.element);
            temp = temp.next;
        }
        //setTemp添加set集合的元素
        Node h = set.head.next;
        while(h!=null){
            setTemp.add(h.element);
            h = h.next;
        }
        return setTemp;
    }

11 、求两个集合的交集

public LinkedSet intersection(LinkedSet set){
        LinkedSet setTemp = new LinkedSet();
        //setTemp添加当前集合的元素
        Node temp = head.next;
        while(temp!=null){      //遍历当前对象的所有结点
            if(set.contains(temp.element)){     //判断set集合是否包含该元素
                setTemp.add(temp.element);      //如果包含该元素,则添加到setTemp中
            }
            temp = temp.next;               //temp指向后继结点
        }   
        return setTemp;
    }

12 、清除集合中的所有元素

    public void clear(){
        length = 0;             //将链表的长度设置为0
        head.next = null;       //将附加头结点的next置为null,如果不置为null,则该链表的元素还存在
    }

总结

单向链表的具体操作还是比较简单的,通过与集合的顺序表相比,我们很明显的发现,链表的插入和删除比顺序表要方便的多,顺序表需要对数组元素进行移动,而链表只需要改变指针域即可。但是对于查找操作来说顺序表效率更高,通过索引即可查找,而链表则需要进行遍历,大大的降低了效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值