【算法题】记一道实现双向链表添加、删除、反序的算法题


题目

记一次高人指点的数据结构(双向链表)
实现以下功能


那么来试试吧~

首先是Node类

  • 为了方便。。测试,加了个有参的构造方法
class Node<T> {
    T value;

    public Node(T value) {
        this.value = value;
    }

    Node<T> next;
    Node<T> pre;
}

接下来就是MyList的具体实现了

class MyList<T> {
    Node<T> head;
    Node<T> tail;
    ...

首先是:尾部新增元素

  • 比较简单,只用判断一下是不是原来没有节点就行,因为要考虑到首尾指针指向首尾节点
    void add(Node<T> element) {
        if (head == null && tail == null) {
            head = tail = element;
        } else {
            element.pre = tail;
            tail.next = element;
            tail = element;
        }
    }

然后是:在指定位置添加元素

  • 因为是双向链表,所以不用遍历到index的前一个位置,直接遍历到index位置就好
  • 然后判断一下是不是首尾节点,如果是的话操作少一半
  • 如果不是的话也很简单。注意一下就是不要指针还没指向节点,节点就丢掉了。。
  • 再注意一下index是否非法的问题。。如果index太大了,就默认在链表尾部添加节点
    //指定位置新增元素
    void add(Node<T> element, int index) {
        if (index < 0) {
            return;
        }
        Node<T> tmp = head;
        // 先遍历到index的前一个
        while (index != 0) {
            if (tmp.next == null && index >= 1) {
                //插在尾部分
                tail.next = element;
                element.pre = tail;
                tail = element;
                return;
            }
            tmp = tmp.next;
            if (tmp == null) {
                return;
            }
            index--;
        }
        // 如果是头结点
        if (tmp == head) {
            element.next = tmp;
            tmp.pre = element;
            head = element;
            return;
        }
        if (tmp == tail) {
            tmp.pre.next = element;
            element.pre = tmp.pre;
            element.next = tmp;
            tmp.pre = element;
            return;
        }
        element.next = tmp;
        element.pre = tmp.pre;
        tmp.pre.next = element;
        tmp.pre = element;
    }

其次是,获取指定位置元素

  • 直接遍历到index位置,进行返回
  • 如果idnex太大或者小于0,返回一个new(值为null)
    //获取指定位置元素
    Node<T> get(int index) {
        if (index < 0) {
            System.out.println("下标小于0");
            return new Node<T>(null);
        }
        Node<T> tmp = head;
        while (index != 0) {
            tmp = tmp.next;
            if (tmp == null) {
                return new Node<T>(null);
            }
            index--;
        }
        return tmp;
    }

删除指定位置的元素

  • 这里也是判断一下是不是首尾节点,以及index下标。原理都是一样的。别搞丢节点就行
    //删除指定位置元素
    Node<T> remove(int index) {
        if (index < 0) {
            return new Node<T>(null);
        }
        Node<T> tmp = head;
        Node<T> remove = head;
        while (index != 0) {
            tmp = tmp.next;
            if (tmp == null) {
                return new Node<T>(null);
            }
            index--;
        }
        remove = tmp;
        if (tmp == tail && tmp == head) {
            head = null;
            tail = null;
            return remove;
        }
        if (tmp == head) {
            tmp = remove.next;
            tmp.pre = null;
            remove.next = null;
            head = tmp;
            return remove;
        }
        if (tmp == tail) {
            tmp = remove.pre;
            tmp.next = null;
            remove.pre = null;
            tail = tmp;
            return remove;
        }
        tmp = remove.pre;
        remove.next.pre = tmp;
        tmp.next = remove.next;
        remove.next = null;
        remove.pre = null;
        return remove;
    }

反序比较复杂

  • 这里使用了三个指针,tmp,tmp2,tmp3进行从尾向头遍历
  • 一边遍历一边反序一个个节点
  • 最后再交换一下原来首尾指针,达到反序的目的!
  • 【还是要记得,别指针还没指向呢,就把节点搞丢了】
    // 链表逆序,原来头部变尾部,第二个元素变倒数第二个元素。。。
    void revert() {
        if (head == tail) {
            return;
        }
        Node<T> tmp = tail.pre;
        Node<T> tmp2 = tail;
        Node<T> tmp3 = tail;
        while (tmp2 != head) {
            tmp2.next = tmp;
            tmp3 = tmp.pre;
            tmp.pre = tmp2;
            tmp.next = null;
            tmp2.pre = null;
            tmp2 = tmp;
            tmp = tmp3;
        }
        tmp = tail;
        tail = head;
        head = tmp;
        head.pre = null;
        tail.next = null;
    }

最简单的输出

  • 几种情况判断一下,结束(0个,1个,多个)别忘记输出最后一个节点哦
    //输出所有元素
    void printElements() {
        if (head == null && tail == null) {
            System.out.println("MyList is Empty!");
        } else {
            if (head == tail) {
                System.out.println(head.value);
                return;
            }
            Node<T> tmp = head;
            while (tmp != tail) {
                System.out.println(tmp.value);
                tmp = tmp.next;
            }
            System.out.println(tmp.value);//输出最后一个节点
        }
    }
}

这里是测试用例,供参考!

public class Test {
    public static void main(String[] args) {
        MyList<Integer> list = new MyList<>();
        Node node1 = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        Node node5 = new Node(5);
        Node node9 = new Node(9);

        list.add(node4);
        list.add(node5);
        list.add(node9, 5);
        list.revert();
        list.printElements();
    }
}

写在最后

反转双链表的操作其实还可以通过O(n)空间复杂度,也就是重新创建一条新链表进行实现,那么时间复杂度和空间复杂度就是双O(n),比较暴力。。最好还是使用指针。
有错还请指正!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值