美文网首页Java数据结构和算法
数据结构和算法-5.1-单链表&有序链表

数据结构和算法-5.1-单链表&有序链表

作者: 今阳说 | 来源:发表于2018-07-04 21:17 被阅读35次

    定义

    • 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的;
    • 链表由多个链结点组成,每个链结点由两部分组成,一个存储数据元素的数据域,一个存储下一个结点地址的指针域;
    • 在链表中,寻找一个特定元素的唯一方法,就是沿着这个元素的链一直向下寻找;

    解决的问题

    无序数组搜索慢,有序数组插入慢,且数组的删除效率低,大小固定;
    链表则常用来替换数组,作为其他存储结构的基础,以解决上面问题;
    除非需要频繁的用下标随机访问各个数据,否则很多地方都可以用链表代替数组。

    分类:

    • 单链表
    • 双端链表
    • 有序链表
    • 双向链表
    • 有迭代器的链表

    单链表的实现(含迭代器)

    1. 创建一个链结点类
    public class Link<T> {
        public T data;//数据域
        public Link<T> next;//指针域, 指向下一个链结点
        //此处next为一个和自己类型相同的字段,因此也叫"自引用"式
    
        public Link(T data) {
            this.data = data;
        }
    
        public void display(){
            System.out.print("Link:{"+data.toString()+"}");
        }
    }
    
    1. 单链表实现类, 其中一些关键的地方都有注释,这里就不再多说了,
    public class LinkList<T> {
        protected Link<T> first;//LinkList仅包含了一个数据项,即对第一个链结点的引用
    
        public boolean isEmpty() {
            return first == null;
        }
    
        /**
         * 向链表插入数据
         *
         * @param value
         */
        public void insertFirst(T value) {
            //新建链结点,把数据传入这个链结点,将这个新的链结点的next字段指向原来的first的值,将first指向这个新的链结点
            Link<T> newLink = new Link<>(value);
            newLink.next = first;
            first = newLink;
        }
    
        public Link<T> deleteFirst() {
            Link temp = first;
            first = first.next;
            return temp;
        }
    
        public void display() {
            System.out.print("LinkList:{ ");
            Link current = first;
            while (current != null) {
                current.display();
                if (current.next != null)
                    System.out.print(", ");
                current = current.next;
            }
            System.out.println("} ");
        }
    
        public Link<T> find(T value) {
            Link current = first;
            //找到才跳出循环,否则一直找,直到next==null,该链结点链表的最后一个
            while (!current.data.equals(value)) {
                if (current.next == null)
                    return null;
                else
                    current = current.next;
            }
            return current;
        }
    
        public Link<T> delete(T value) {
            Link current = first;//当前链结点
            Link previous = first;//当前值的前一个链结点
            if (current == null)
                return null;
            //找到才跳出循环,否则一直找,直到next==null,该链结点链表的最后一个
            while (!current.data.equals(value)) {
                if (current.next == null)
                    return null;
                else {
                    previous = current;
                    current = current.next;
                }
            }
            if (current == first)
                //如果所找的值对应first链结点,就把first指向下一个链结点,也就是first.next
                first = first.next;
            else
                //如果不是对应first,就把该链结点的前一个链结点的指针next指向该链结点的下一个链结点,即current.next
                previous.next = current.next;
            return current;
        }
    
        public LinkIterator<T> iterator(){
            return new LinkIterator<>(this);
        }
    
        public Link<T> getFirst() {
            return first;
        }
    }
    

    上面的LinkIterator迭代器类的实现如下:

    public class LinkIterator<T> {
        private LinkList<T> linkList;
        private Link<T> current;
        private Link<T> previous;
    
        public LinkIterator(LinkList<T> linkList) {
            this.linkList = linkList;
            reset();
        }
    
        private void reset() {
            current=linkList.getFirst();
            previous=null;
        }
    
        public Link<T> getCurrent() {
            return current;
        }
    
        public boolean hasNext(){
            return current!=null&&current.next!=null;
        }
    
        public Link<T> next(){
            previous=current;
            current=current.next;
            return previous;
        }
    
        public void remove(){
            if (current==linkList.first)
                linkList.first=linkList.first.next;
            else
                previous.next=current.next;
        }
    
    }
    
    
    1. 对单链表实现类的使用
      private static void testLinkList() {
            LinkList<String> linkList = new LinkList<>();
            for (int i = 0; i < 10; i++) {
                linkList.insertFirst("data_" + i);
                linkList.display();
            }
            linkList.find("data_3").display();
            linkList.delete("data_5").display();
            linkList.delete("data_7").display();
            linkList.delete("data_8").display();
            linkList.display();
       }
    
    1. 迭代器的使用
      private static void testLinkIterator() {
            LinkList<String> linkList = new LinkList<>();
            for (int i = 0; i < 10; i++) {
                linkList.insertFirst("data_" + i);
                linkList.display();
            }
            System.out.println("----> iterator:");
            LinkIterator<String> iterator = linkList.iterator();
            while (iterator.hasNext()) {
                Link<String> link = iterator.getCurrent();
                link.display();
                System.out.println();
                if (link.data.equals("data_6")) {
                    iterator.remove();
                }
                iterator.next();
            }
            linkList.display();
        }
    
    1. 之前介绍栈时有提到可以使用链表实现:将ArrayStack中的数组替换为LinkList,push用insertFirst实现,pop用deleteFirst实现,也是完全可以的,实现代码如下:
    public class LinkStack<T> extends Stack<T> {
    
        private LinkList<T> linkList;
    
        public LinkStack() {
            linkList =new LinkList();
        }
    
        @Override
        public boolean isEmpty() {
            return linkList.getFirst()==null;
        }
    
        @Override
        public void push(T value) {
            linkList.insertFirst(value);
        }
    
        @Override
        public T pop() {
            return linkList.deleteFirst().data;
        }
    
        @Override
        public T peek() {
            return linkList.getFirst().data;
        }
    
        @Override
        public void display() {
            System.out.print("LinkStacker: ");
            linkList.display();
        }
    }
    

    有序链表

    • 数据项按照关键值有序排列
    • 之前有用有序数组实现优先级队列,然而使用有序链表也是可以实现的
    • 提供一种新的数组排序算法:表插入排序
      有序链表可以用于一种高效的排序机制,假设有一个无序数组,如果从这个数组中取出数据,然后一个一个的插入有序链表,他们自动的按顺序排列,把它们从有序表中删除,重新放入数组,那么数组就排好序了,这种排序方式比常用的插入排序效率更高些;
    • 那么为什么不直接用有序数组呢?有序链表的插入效率要优于有序数组,因为不需要移动元素;而且链表所占用内存是充分利用的,而且扩充方便,不用担心角标越界问题;
    • 有序链表的实现
    public class OrderedLinkList<T extends Comparable<T>> extends LinkList<T> {
        public void insert(T value) {
            Link<T> newLink = new Link<>(value);
            Link<T> previous = null;
            Link<T> current = first;
            while (current != null && value.compareTo(current.data) > 0) {
                previous = current;
                current = current.next;
            }
            if (previous == null)
                first = newLink;
            else
                previous.next = newLink;
            newLink.next = current;
        }
    
        public Link<T> find(T value) {
            Link<T> current = first;
            while (current != null && current.data.compareTo(value) <= 0) {
                if (current.data == value)
                    return current;
                current = current.next;
            }
            return null;
        }
    
        public Link<T> delete(T value) {
            Link<T> previous = null;//当前值的前一个链结点
            Link<T> current = first;//当前链结点
            while (current != null && current.data.compareTo(value) < 0) {
                previous = current;
                current = current.next;
            }
            if (current.data != value)
                return null;
            if (current == first)
                //如果所找的值对应first链结点,就把first指向下一个链结点,也就是first.next
                first = first.next;
            else
                //如果不是对应first,就把该链结点的前一个链结点的指针next指向该链结点的下一个链结点,即current.next
                previous.next = current.next;
            return current;
        }
    }
    
    

    相关文章

      网友评论

        本文标题:数据结构和算法-5.1-单链表&有序链表

        本文链接:https://www.haomeiwen.com/subject/zkpyuftx.html