通过Java实现数据结构—链表

一、链表

        链表作为数据结构中重要的组成部分,其相较于不易于增删操作的顺序表而言,在逻辑和空间上都具有更高的灵活性。以下将通过Java实现单向不带头非循环链表并实现增、删、查找、获取大小、展示、清空方法。

二、代码结构

       

1.AddIndexPosIlegalException:自定义运行时异常类,用于在输入下标非法时抛出异常。

2.SingleLinkedList(包含内部类ListNode:定义节点的数值域和引用域):包含头节点引用以及各种链表方法。

3.Test:其main方法用于测试链表操作。

三、程序源码

1.AddIndexPosIlegalException类:

//定义下标添加异常类AddIndexPosIlegalException
public class AddIndexPosIlegalException extends RuntimeException{
    public AddIndexPosIlegalException(){
        super();
    }
    public AddIndexPosIlegalException(String msg){
        super(msg);
    }
}

值得注意的是该异常属于运行时异常,应当继承RuntimeException。

2.SingleLinkedList类:

(1)定义:

public class SingleLinkedList

(2)成员变量:

private ListNode head=null;//头节点引用本地初始化为空

(3)定义节点内部类ListNode(当然类外定义也可以):

class ListNode{
        //数值域
        public int val;
        //引用域
        public ListNode next;

        //Node类的有参构造方法
        public ListNode(int val){
            this.val=val;
            this.next=null;
        }
    }

(4)头插方法:

//头插法
    public void addFirst(int data){
        ListNode listNode=new ListNode(data);
        listNode.next=head;
        head=listNode;
    }

(5)尾插方法:

//尾插法
    public void addLast(int data){
        ListNode listNode=new ListNode(data);
        //判断头节点是否为空,为空则直接添加
        if(head==null){
            head=listNode;
        }
        //遍历链表找到最后一个节点
        ListNode current=head;
        while(current.next!=null){
            current=current.next;
        }
        current.next=listNode;

    }

(6) 在指定下标插入数据(包含判断下标是否合法以及寻找直接前驱节点两个底层方法):

//底层方法,检查下标
    public void checkIndex(int index)throws AddIndexPosIlegalException{
        if(index<0||index>getSize()){
            throw new AddIndexPosIlegalException("下标非法");
        }
    }

    //底层方法,寻找某个下标直接前驱节点
    public ListNode findSuboneIndex(int index){
        ListNode current=head;
        int count=0;
        while(count!=index-1){
            current=current.next;
            count++;
        }
        return current;
    }


    //在指定下标插入数据
    public void addIndex(int index,int data){
        //解决下标非法异常
        try{
            checkIndex(index);
        }catch (AddIndexPosIlegalException e){
            e.printStackTrace();
        }
        //找到直接前驱节点
        ListNode subOneListNode=findSuboneIndex(index);
        //插入新节点
        ListNode listNode=new ListNode(data);
        listNode.next=subOneListNode.next;
        subOneListNode.next=listNode;

    }

(7)删除第一次出现值为key的节点方法:

 //删除第一次出现的值为key的节点
    public void remove(int key) {
        //判空
        if(head==null){
            return;
        }
        ListNode current = head;
        //后续以head.next判断的形式进行遍历无法涉及到开始节点
        //所以要对开始节点进行处理
        if (current.val == key) {
            head = null;
            return;
        }
        while (current.next != null) {
            if (current.next.val == key) {
                current.next = current.next.next;
                return;
            }
            current=current.next;
        }
    }

(8)删除所有值为key的节点方法:

 //删除所有值为key的节点
    public void removeAllKey(int key){
        //判空
        if(head==null){
            return;
        }
        //双引用遍历链表
        ListNode pre=head;
        ListNode cur=head.next;
        while(cur!=null){
            if(cur.val==key) {
                pre.next = cur.next;
            }else{
                pre=cur;
            }
            cur=cur.next;
        }
        //双引用遍历并没有涉及到头节点,所以最后对头节点进行处理
        if(head.val==key) {
            head = head.next;
        }
    }

(9)查找链表中是否包含某值的方法:

//查找链表中是否包含某值
    public boolean contains(int key){
         ListNode current=head;
         while(current!=null){
             if(current.val==key){
                 return true;
             }
         }
        return false;
    }

(10)获取链表大小(长度)的方法:

//获取链表的长度
    public int getSize(){
        ListNode current=head;
        int count=0;
        //遍历全部链表
        while(current!=null){
            count++;
            current=current.next;
        }
        return count;
    }

(11)展示整个链表的方法:

//展示整个链表
    public void display(){
        ListNode current=head;
        //遍历全部链表
        while(current!=null){
            System.out.print(current.val+" ");
            current=current.next;
        }
        System.out.println();
    }

(12)清空整个链表的方法:

//清空整个链表
    public void clear(){
        //判空
        if(head==null){
            return;
        }
        //双引用遍历全部链表
        ListNode cur=head;
        ListNode suc=head.next;
        while(suc!=null){
            cur.next=null;
            cur=suc;
            suc=suc.next;
        }
        cur=null;
        head=null;
    }

四、操作示例

Test中源码为:

public class Test {
    public static void main(String[] args) {
        //创建链表
        SingleLinkedList singleLinkedList=new SingleLinkedList();
        //头插演示
        singleLinkedList.addFirst(1);
        singleLinkedList.addFirst(2);
        singleLinkedList.addFirst(3);
        singleLinkedList.addFirst(4);
        //尾插演示
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(1);
        singleLinkedList.addLast(1);
        singleLinkedList.display();
        System.out.println("****************");

        //删除第一个值为key的节点
        singleLinkedList.remove(2);
        singleLinkedList.display();
        System.out.println("****************");

        //删除所有值为key的节点
        singleLinkedList.removeAllKey(1);
        singleLinkedList.display();
        System.out.println("****************");

        //指定位置插入演示
        singleLinkedList.addIndex(1,10);
        singleLinkedList.display();
        System.out.println("****************");

        //获取大小演示
        System.out.println("链表大小为"+singleLinkedList.getSize());
        System.out.println("****************");

        //清空演示
        singleLinkedList.clear();
        singleLinkedList.display();
    }
}

运行结果如下:

注:最后一行打印为空说明链表已经清空。

五、小结

以上便是通过java实现单向不带头非循环链表的全部内容,部分思路来自互联网,如有不当,敬请斧正!

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值