Java 单链表应用一

设计一个链表结构来对数组进行排序,并可以添加删除节点

1. 链表结构

class MyLink {
    public int data;
    public MyLink next;

    /* 构造函数 */
    public MyLink(int data) {
        super();
        this.data = data;
    }

    /* 重载toString方法 */
    @Override
    public String toString() {
        return "[[data="+ this.data + "]]";
    }
}

包含一个构造函数、重载了toString方法,方便之后创建新的节点,以及打印节点数据。

2. 插入一个单节点

插入新节点时,从首节点开始遍历,直到遇到比当前节点大的节点为止。

private void insertMyLink(int data) {
    MyLink newNode = new MyLink(data);
    MyLink current = firstLink; // 定义一个当前节点,并指向首节点
    MyLink previous = null; // 定义先前结点 将previous赋为null

    /* 定位到需要插入的位置,previous之后 */
    while((current != null) && (current.data < newNode.data)) {
        previous = current;
        current = current.next;
    }

    /* 插入节点 */
    if (previous == null) { // 插在链表首部需要特殊处理
        newNode.next = firstLink;
        firstLink = newNode;
    } else { // 包括插入两节点之间和插在链表尾部两种情况
        previous.next = newNode;
        newNode.next = current;
    }
    nodeCount++; // 插入成功之后,总节点数加一
}

但是这样实现肯定会有一个问题,那就是会重复添加节点

比如添加int n1[] = {4,5,4,1};,就会出现下面的现象

==========START==========
[[data=1]]
[[data=4]]
[[data=4]]
[[data=5]]
==========END==========

所以,我这里做了一下判断是否重复的操作

private boolean isRepetitive(MyLink current, MyLink newNode) {
    /* 这里提前判空,避免插入链表最后时出现current为null */
    if (current != null && current.data == newNode.data) {
        return true;
    }
    return false;
}

插入节点之前判断一下是否重复

/* 插入新节点 */
private void insertMyLink(int data) {
    MyLink newNode = new MyLink(data);
    MyLink current = firstLink; // 定义一个当前节点,并指向首节点
    MyLink previous = null; // 定义先前结点 将previous赋为null

    /* 定位到需要插入的位置,previous之后 */
    while((current != null) && (current.data < newNode.data)) {
        previous = current;
        current = current.next;
    }

    /* 插入节点 */
    if (!isRepetitive(current, newNode)) {
        if (previous == null) { // 插在链表首部需要特殊处理
            newNode.next = firstLink;
            firstLink = newNode;
        } else { // 包括插入两节点之间和插在链表尾部两种情况
            previous.next = newNode;
            newNode.next = current;
        }
        nodeCount++; // 插入成功之后,总节点数加一
    }
}

加入判断之后就可以去重重复的节点。

==========START==========
[[data=1]]
[[data=4]]
[[data=5]]
==========END==========

3. 删除首节点

删除之前要进行判空,否则在获取firstLink.next的时候可能会出现Cannot read field "next" because "this.firstLink" is null

/* 删除首节点 */
private void removeFirstLink() {
    if (firstLink != null) {
        firstLink = firstLink.next;
        nodeCount--; // 删除成功时,总节点数减一
    }
}

4. 打印链表数据

使用这种数据结构的好处就是,遍历和删除节点的时间复杂度为O(n)。

/* 打印出所有数据 */
public void printMyLink() {
    System.out.println("==========START==========");
    MyLink current = firstLink;
    while (current != null) {
        System.out.println(current);
        current = current.next;
    }
    System.out.println("==========END==========");
}

5. 应用

给定指定的数组(numbers[]),选出两个最小的值并求出最小公倍数,将这两个数删除,并把求出的最小公倍数加入到数组中。给定一个阀值(target),当数组中所有的值都大于阀值的时候返回求最小公倍数的次数;若给定的数组剩下一个数据时,仍小于阀值,返回-1;若数组中的最小值大于阀值,返回0。

class MyLink {
    public int data;
    public MyLink next;

    /* 构造函数 */
    public MyLink(int data) {
        super();
        this.data = data;
    }

    /* 重载toString方法 */
    @Override
    public String toString() {
        return "[[data="+ this.data + "]]";
    }
}

class MyLinkSort {
    private MyLink firstLink; // 首结点
    private int nodeCount; // 整个链表的节点数目
    public MyLinkSort() {
        firstLink = null;
    }

    public MyLinkSort(int nums[]) {
        for (int i = 0; i < nums.length; i++) {
            insertMyLink(nums[i]);
        }
    }

    /* 去除重复的节点 */
    private boolean isRepetitive(MyLink current, MyLink newNode) {
        /* 这里提前判空,避免插入链表最后时出现current为null */
        if (current != null && current.data == newNode.data) {
            return true;
        }
        return false;
    }

    /* 插入新节点 */
    private void insertMyLink(int data) {
        MyLink newNode = new MyLink(data);
        MyLink current = firstLink; // 定义一个当前节点,并指向首节点
        MyLink previous = null; // 定义先前结点 将previous赋为null

        /* 定位到需要插入的位置,previous之后 */
        while((current != null) && (current.data < newNode.data)) {
            previous = current;
            current = current.next;
        }

        /* 插入节点 */
        if (!isRepetitive(current, newNode)) {
            if (previous == null) { // 插在链表首部需要特殊处理
                newNode.next = firstLink;
                firstLink = newNode;
            } else { // 包括插入两节点之间和插在链表尾部两种情况
                previous.next = newNode;
                newNode.next = current;
            }
            nodeCount++;
        }
    }

    /* 删除首节点 */
    private void removeFirstLink() {
        if (firstLink != null) {
            firstLink = firstLink.next;
            nodeCount--;
        }
    }

    /* 打印出所有数据 */
    public void printMyLink() {
        System.out.println("==========START==========");
        MyLink current = firstLink;
        while (current != null) {
            //current.printLink();
            System.out.println(current);
            current = current.next;
        }
        System.out.println("==========END==========");
    }

    public void insertAndRemoveFirst(int data) {
        removeFirstLink();
        removeFirstLink();
        insertMyLink(data);
    }
    public int getNodeCount() {
        return nodeCount;
    }
    public int getFirstLinkNodeData() {
        return firstLink.data;
    }
    public int getFirstLinkNextNodeData() {
        return firstLink.next.data;
    }

    public static void main(String[] args) {
        int n1[] = {4,5,4,1};
        MyLinkSort myLinkSort = new MyLinkSort(n1);
        myLinkSort.printMyLink();
    }
}

public class T2_improve {
    private boolean bIsEnd(int target, MyLinkSort myLinkSort) {
        if (myLinkSort.getFirstLinkNodeData() >= target) {
            return true;
        }
        return false;
    }

    private int getGCD(int a, int b) {
        int getGCD = (a % b == 0) ? b : getGCD(b, a % b);
        return getGCD;
    }

    /* 获取最大公约数 */
    private int getLCM(int a, int b) {
        int getLCM = (a * b) / getGCD(a, b);
        return getLCM;
    }

    private int numOperations(int target, int[] numbers) {
        MyLinkSort myLinkSort = new MyLinkSort(numbers);
        return myFun(target, myLinkSort, 0);
    }

    public int myFun(int target, MyLinkSort myLinkSort, int count) {

        if (bIsEnd(target, myLinkSort)) {
            return count;
        }
        if (myLinkSort.getNodeCount() == 1) {
            if (myLinkSort.getFirstLinkNodeData() < target) {
                return -1;
            }
            return count;
        }

        /* 获取最小的两个数的最大公约数 */
        int lcm = getLCM(myLinkSort.getFirstLinkNodeData(), myLinkSort.getFirstLinkNextNodeData());
        myLinkSort.insertAndRemoveFirst(lcm);
        count++;
        return myFun(target, myLinkSort, count);
    }

    public static void main(String[] args) {
        int n1[] = {4,5,4,1};
        int n2[]={4,4,4,4,4};
        int n3[]={100,300};
        int n4[]={5,1,9,16,23};
        T2_improve t = new T2_improve();
        System.out.println(t.numOperations(3,n1));
        System.out.println(t.numOperations(8,n2));
        System.out.println(t.numOperations(99,n3));
        System.out.println(t.numOperations(45,n4));
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值