JAVA实现单链表的增删改查

前言

实现参考:

http://blog.csdn.net/hitwhylz/article/details/12305021

http://www.cnblogs.com/smyhvae/p/4761593.html

建议阅读以上博客,我的博客更偏向于[我]能看懂
上面的博客则偏向于[大家]都能看懂

实现的功能

增加

  • 指定位置插入节点
  • 在末尾增加节点

删除

  • 删除指定节点,通过节点数据(假设数据不重复)
  • 删除指定位置节点

修改

  • 修改指定位置节点数据

查询

  • 查询某个节点的位置
  • 查询某个位置中的节点数据
  • 查询某个数据是否存在于链表中(假设数据不重复)

转数组

  • 将链表转成数组

中文版伪代码

/**
 *
 * 单向链表
 *      节点:
 *          数据都存放在一个节点中
 *          每个节点都有指向下一个节点的指针
 *      头指针:
 *          链表中的头个节点,不计入节点数,表示链表头
 *      当前指针:
 *        在链表中游走,指向哪,跑到哪。
 * 增加
 *      新增节点到尾部时
 *          空链表:新增的节点成为头指针的next指向的节点
 *          非空链表:成为最后一个节点的下一个节点,更新当前指针为下一个节点
 *      新增节点到第n个位置时
 *          如果插入的位置不是头:
 *              到达第n-1个节点
 *              新节点指向第n-1个的next节点
 *              第n-1个节点的next指向新节点
 *          如果是第一个位置(头):
 *              新节点的next指向头指针的节点
 *              更新头指针的next指向新节点
 * 删除
 *      根据数据删除
 *          判断数据是否存在或者是否为空
 *              如果存在,且位置为n
 *                  将当前指针指向第n-1个节点
 *                  更新第n-1个节点的next指向第n+1个节点
 *              否则
 *                  抛出异常
 *      根据传入的位置n删除
 *          判断参数n是否合法   (n >= 0 && n < size)
 *              若合法
 *                  将当前指针指向第n-1个节点
 *                  更新第n-1个节点的next指向第n+1个节点
 *               否则
 *                  抛出异常
 *
 * 查询
 *      根据数据查询节点位置
 *          判断输入数据的合法性
 *          合法
 *              遍历查找
 *              找到,返回位置
 *              没找到,返回-1
 *      获取准确数据,根据传入位置n查询
 *          判断输入数据的合法性
 *              定位到n,返回数据
 *      存在性查询,根据传入数据查询链表中是否存在这样一个节点
 *          判断输入数据的合法性
 *              遍历查询
 *              存在,返回真
 *              不存在,返回假
 * 修改
 *      传入数据和位置
 *      验证位置的合法性
 *      合法
 *          当前指针跳转到目标节点修改
 *          返回真
 *      不合法
 *          返回假
 */

具体实现

public class SingleLinkedList<T> {

    private Node headNode;
    private Node currNode;
    private int size;

    SingleLinkedList() {
        headNode = new Node();
        currNode = null;
        size = 0;
    }

    public int Size() {
        return size;
    }

    //添加节点到链表尾部
    public void insert(T data) {
        Node tNode = new Node(data);
        if (isEmpty()) {
            headNode.setNext(tNode);
        } else {
            toIndexOf(size - 1);
            currNode.setNext(tNode);
        }
        size++;
    }

    //添加节点到第n个位置
    public void insert(T data, int n) {
        //将当前指针定位到第n-1个节点
        toIndexOf(n - 1);

        //如果为空,插入到第一个节点
        if (isEmpty()) {
            insert(data);
            return;
        }

        // 将新节点的next指向第n个节点, 第n-1个节点的next指向新节点
        // 即新节点为第n个,原第n个节点为n+1
        currNode.setNext(new Node(data, currNode.getNext()));
        size++;
    }

    //查询第n个节点的数据
    public <T> T get(int n) {
        //当前指针移动到第n个节点
        toIndexOf(n);
        return (T) currNode.getData();
    }

    //查询某节点的位置
    public int getElemAt(T data) {
        if (data == null) {
            throw new NullPointerException("既然喜欢null,那就给你咯。");
        }
        currNode = headNode.getNext();
        int i = 0;
        while (currNode != null) {
            if (currNode.getData().equals(data)) {
                return i;
            }
            i++;
            currNode = currNode.getNext();
        }
        return -1;
    }

    //修改节点的数据
    public boolean setElemAt(T data, int n) {
        toIndexOf(n);
        currNode.setData(data);
        return true;
    }

    //查询某节点是否存在
    public boolean contains(T data) {

        return getElemAt(data) == -1 ? false : true;
    }

    //删除第n个节点
    public T delete(int n) {
        toIndexOf(n - 1);
        T data = currNode.getNext().getData();
        currNode.setNext(currNode.getNext().getNext());
        size--;
        return data;
    }

    //删除指定节点
    public T deleteElemBy(T data) {
        int n = getElemAt(data);
        return delete(n);
    }

    public boolean isEmpty() {
        return size == 0 ? true : false;
    }

    //将其转为数组
    public Object[] toArray() {
        if (isEmpty()) {
            throw new IndexOutOfBoundsException("Size: " + size);
        }
        Object[] arr = new Object[size];
        toIndexOf(0);
        int i = 0;
        while (currNode != null) {
            arr[i++] = currNode.getData();
            currNode = currNode.getNext();
        }
        return arr;
    }

    //将当前指针移动到指定位置
    private void toIndexOf(int n) {
        if (isEmpty() || !isIndexOk(n)) {
            throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + size);
        }
        currNode = headNode;
        if (n == -1) return;

        while (n != -1) {
            currNode = currNode.getNext();
            n--;
        }
    }

    private boolean isIndexOk(int n) {
        if (n < -1 || n >= size) return false;
        return true;
    }

    private class Node {
        private T data;
        private Node next;

        Node() {
        }

        Node(T data) {
            this.data = data;
        }

        Node(T data, Node nextNode) {
            this.data = data;
            this.next = nextNode;
        }

        public T getData() {
            return data;
        }

        public Node getNext() {
            return next;
        }

        public void setData(T data) {
            this.data = data;
        }

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

测试

public class LinkedListTest {
    public static void main(String[] args) {
        SingleLinkedList<Integer> test = new SingleLinkedList<Integer>();
        for (int i = 0; i < 10; i++) {
            test.insert(i);
        }

        //System.out.println("------------越界测试--------------");
        //System.out.println(test.get(-1));
        //System.out.println(test.get(test.Size()));
        System.out.println("角标读取:");
        System.out.print(test.get(0) + ",");
        System.out.print(test.get(4) + ",");
        System.out.println(test.get(test.Size() - 1));

        System.out.println("------------转换数组--------------");
        Object[] data = test.toArray();
        showArray(data);


        System.out.println("------------根据元素获取角标--------------");
        int el1 = 2, el2 = 22;
        System.out.println(el1 + " at " + test.getElemAt(2));
        System.out.println(el2 + " at " + test.getElemAt(22));

        System.out.println("------------原数组--------------");
        data = test.toArray();
        showArray(data);
        System.out.println("角标删除测试,删除");
        System.out.print(test.delete(9) + ",");
        System.out.print(test.delete(0) + ",");
        System.out.println(test.delete(3));
        System.out.println("删除完毕");
        data = test.toArray();
        showArray(data);

        System.out.println("元素删除测试,删除:");
        System.out.print(test.deleteElemBy(1) + ",");
        System.out.print(test.deleteElemBy(8) + ",");
        System.out.println(test.deleteElemBy(5));
        System.out.println("删除完毕:");
        data = test.toArray();
        showArray(data);
        System.out.println("------------包含测试--------------");
        data = test.toArray();
        showArray(data);
        int n1 = 6, n2 = 10;
        System.out.println(n1 + ",在吗?" + test.contains(n1));
        System.out.println(n2 + ",在吗?" + test.contains(n2));

        System.out.println("------------插入测试--------------");
        data = test.toArray();
        showArray(data);
        test.insert(4, 2);
        test.insert(5, 3);
        System.out.println("插入4、5分别到第2、3个位置,完成:");
        data = test.toArray();
        showArray(data);

        System.out.println("------------修改测试--------------");
        data = test.toArray();
        showArray(data);
        test.setElemAt(1024, 2);
        test.insert(2048, 3);
        System.out.println("修改角标2、3分别到为1024、2048,完成:");
        data = test.toArray();
        showArray(data);
        test.setElemAt(6, 10);
    }

    public static void showArray(Object[] data) {
        int len = data.length - 1;
        for (int i = 0; i <= len; i++) {
            System.out.print(data[i]);
            System.out.print(i < len ? " " : "");
        }
        System.out.println();
    }
}

结果

角标读取:
0,4,9
------------转换数组--------------
0 1 2 3 4 5 6 7 8 9
------------根据元素获取角标--------------
2 at 2
22 at -1
------------原数组--------------
0 1 2 3 4 5 6 7 8 9
角标删除测试,删除
9,0,4
删除完毕
1 2 3 5 6 7 8
元素删除测试,删除:
1,8,5
删除完毕:
2 3 6 7
------------包含测试--------------
2 3 6 7
6,在吗?true
10,在吗?false
------------插入测试--------------
2 3 6 7
插入45分别到第23个位置,完成:
2 3 4 5 6 7
------------修改测试--------------
2 3 4 5 6 7
修改角标23分别到为10242048,完成:
2 3 1024 2048 5 6 7
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 10, Size: 7
    at SingleLinkedList.toIndexOf(SingleLinkedList.java:183)
    at SingleLinkedList.setElemAt(SingleLinkedList.java:135)
    at LinkedListTest.main(LinkedListTest.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

收获

第一次用泛型(大概是乱用)

静态内部类和非静态内部类的区别
静态内部类不能访问外部类的非静态成员
类似于把静态内部类独立了

意识到链表的各种操作十分耗时!!查询一个,查一个就要循环遍历一遍也是没谁了。

脑海里多了个概念,一个类似游标指针的概念,指定它去哪个位置就去哪个位置获取元素,不知道叫游标合适不合适,总之游标很忙。在我的实现里的currNode就是经常跑头跑尾。

把链表操作完转成数组会提高效率,也许?

发现自己对异常不熟悉到大脑一片空白

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值