在正常的工做中,咱们常常遇到从消息队列中接收一天的数据量,并对其进行排序的场景。那么,咱们一般会想到最经典的十大经典排序算法
。确实,这些算法均可以知足咱们的场景须要,,但若是咱们要求接收消息过程当中,实时进行排序呢?这些算法显然都不能知足需求,它们都是在接收到全部数据后,再统一排序。因此,今天,咱们动手本身遍写一个实时插入排序算法!html
参考插入排序
算法,咱们将接收到的数据存放在一个链表结构当中,每接收一个新数据,就让它与已存在的数据逐个比较,找到须要插入的位置下一个节点,执行新节点插入操做!java
由于要进行排序,因此咱们须要先创建一个比较器接口,来保证用户自定义比较方法。node
package cn.wxson.sort.comparator; import cn.wxson.sort.node.AbstractNode; import com.sun.istack.internal.NotNull; /** * Title 比较器 * * @author Ason(18078490) * @date 2020-08-03 */ @FunctionalInterface public interface AbstractComparator<T> { /** * 比较方法 * * @param one 数据节点一 * @param two 数据节点二 * @return 比较结果 */ boolean compare(@NotNull AbstractNode<T> one, @NotNull AbstractNode<T> two); }
建立节点抽象类,存放数据,并利用比较器实现比较逻辑。算法
package cn.wxson.sort.node; import cn.wxson.sort.comparator.AbstractComparator; import lombok.Getter; import lombok.Setter; /** * Title 节点 * * @author Ason(18078490) * @date 2020-08-03 */ @Setter @Getter public abstract class AbstractNode<T> { /** * 前一个节点 */ private AbstractNode<T> pre; /** * 后一个节点 */ private AbstractNode<T> next; /** * 节点内存储的实际数据 */ protected T t; /** * 无参构造 */ public AbstractNode() { super(); } /** * 带参构造 * * @param t 数据对象 */ public AbstractNode(T t) { this.t = t; } /** * 获取数据比较器 * * @return 比较器对象 */ protected abstract AbstractComparator<T> comparator(); /** * 数据比较 * * @param data 数据节点 */ public AbstractNode<T> compareTo(AbstractNode<T> data) { return this.comparator().compare(this, data) ? this : this.next.compareTo(data); } }
头节点是一个虚拟节点,只作传递给下个节点操做,自身实现比较器,数据比较时永远排在第一位。json
package cn.wxson.sort.node; import cn.wxson.sort.comparator.AbstractComparator; /** * Title 虚拟头节点 * 只作传递给下个节点操做,数据比较永远排在第一位 * * @author Ason(18078490) * @date 2020-08-03 */ public final class DummyHeadNode<T> extends AbstractNode<T> implements AbstractComparator<T> { /** * 获取数据比较器 * * @return 比较器对象 */ @Override protected AbstractComparator<T> comparator() { return this; } /** * 比较方法 * 头节点永远排在第一位 * * @param one 节点一 * @param two 节点二 * @return 比较结果 */ @Override public boolean compare(AbstractNode<T> one, AbstractNode<T> two) { return false; } }
尾节点也是一个虚拟节点,不须要作任务传递操做,自身实现比较器,排序时永远排在链表最后一位。数据结构
package cn.wxson.sort.node; import cn.wxson.sort.comparator.AbstractComparator; /** * Title 虚拟尾节点 * 由于是最后一个节点,因此,不须要作任务传递操做,永远排在链表最后一位 * * @author Ason(18078490) * @date 2020-08-03 */ public final class DummyTailNode<T> extends AbstractNode<T> implements AbstractComparator<T> { /** * 获取数据比较器 * * @return 比较器对象 */ @Override protected AbstractComparator<T> comparator() { return this; } /** * 比较方法 * 尾节点永远排在最后一位 * * @param one 节点一 * @param two 节点二 * @return 比较结果 */ @Override public boolean compare(AbstractNode<T> one, AbstractNode<T> two) { return true; } }
普通节点将接收用户自定义比较器进行数据比较。app
package cn.wxson.sort.node; import cn.wxson.sort.comparator.AbstractComparator; /** * Title 普通节点 * * @author Ason(18078490) * @date 2020-08-03 */ public class CommonNode<T> extends AbstractNode<T> { /** * 比较器 * 是普通节点必须的比较工具 */ private AbstractComparator<T> comparator; /** * 带参构造 * * @param data 数据 */ public CommonNode(T data) { super(data); } /** * 注册比较器 * * @param comparator 比较器 */ public void register(AbstractComparator<T> comparator) { this.comparator = comparator; } /** * 获取数据比较器 * * @return 比较器对象 */ @Override protected AbstractComparator<T> comparator() { return this.comparator; } }
链表结构抽象类中存在虚拟头节点和虚拟尾节点,并实现链表全部遍历功能。ide
package cn.wxson.sort.biz; import cn.wxson.sort.node.AbstractNode; import cn.wxson.sort.node.DummyHeadNode; import cn.wxson.sort.node.DummyTailNode; import com.google.common.collect.Lists; import java.util.List; /** * Title 链表结构抽象类 * 作初始化链表、表元素遍历等操做 * * @author Ason(18078490) * @date 2020-08-03 */ public class AbstractLinkedList<T> { /** * 虚拟头节点 */ protected final AbstractNode<T> dummyHeadNode; /** * 虚拟尾节点 */ protected final AbstractNode<T> dummyTailNode; /** * 无参构造 * 初始化链表的头尾虚拟节点 */ public AbstractLinkedList() { // 建立虚拟头节点、虚拟尾节点,并将它们关联起来 this.dummyHeadNode = new DummyHeadNode<>(); this.dummyTailNode = new DummyTailNode<>(); this.dummyHeadNode.setNext(this.dummyTailNode); this.dummyTailNode.setPre(this.dummyHeadNode); } /** * 除虚拟头节点、虚拟尾节点外,是否包含其余节点 * * @return 断定结果 */ public boolean hasNext() { return this.dummyHeadNode.getNext() != this.dummyTailNode; } /** * 获取链表元素 * * @return 元素集合 */ public List<T> list() { List<T> result = Lists.newLinkedList(); AbstractNode<T> pos = this.dummyHeadNode.getNext(); while (pos != this.dummyTailNode) { result.add(pos.getT()); pos = pos.getNext(); } return result; } /** * toString方法 * * @return 字符串 */ @Override public String toString() { // 不存在元素时,返回空集合 if (!hasNext()) { return "[]"; } // 存在元素时,逐个打印 StringBuilder sb = new StringBuilder("["); AbstractNode<T> pos = this.dummyHeadNode.getNext(); while (pos != this.dummyTailNode) { sb.append(pos.getT().toString()).append(","); pos = pos.getNext(); } String result = sb.substring(0, sb.lastIndexOf(",")); return result + "]"; } }
链表结构类中,在新增元素时,注册比较器,进行比较后,实现实时插入操做。工具
package cn.wxson.sort.biz; import cn.wxson.sort.comparator.AbstractComparator; import cn.wxson.sort.node.AbstractNode; import cn.wxson.sort.node.CommonNode; /** * Title 链表结构类 * 功能:从头结点向后进行比较 * * @author Ason(18078490) * @date 2020-08-03 */ public class LinkedList<T> extends AbstractLinkedList<T> { /** * 比较器 */ private final AbstractComparator<T> comparator; /** * 带参构造 * * @param comparator 比较器 */ public LinkedList(AbstractComparator<T> comparator) { // 初始化链表 super(); // 注入比较器 this.comparator = comparator; } /** * 新增元素 * * @param data 数据 */ public void add(T data) { // 建立新节点,并注册比较器 CommonNode<T> newNode = new CommonNode<>(data); newNode.register(this.comparator); // 从头节点开始,找到新节点应该插入的位置的下一个节点 AbstractNode<T> next = dummyHeadNode.compareTo(newNode); // 将新节点插入链表 AbstractNode<T> pre = next.getPre(); newNode.setPre(pre); newNode.setNext(next); pre.setNext(newNode); next.setPre(newNode); } }
咱们新建几个用户类,来根据用户年龄进行实时排序测试。学习
package cn.wxson.sort.test; import com.alibaba.fastjson.JSON; import lombok.Builder; import lombok.Getter; import lombok.Setter; /** * Title 用户类 * * @author Ason(18078490) * @date 2020-08-03 */ @Getter @Setter @Builder public class User { private String name; private int age; @Override public String toString() { return JSON.toJSONString(this); } }
package cn.wxson.sort.test; import cn.wxson.sort.biz.LinkedList; import lombok.extern.slf4j.Slf4j; /** * Title 测试类 * * @author Ason(18078490) * @date 2020-08-03 */ @Slf4j public class Domain { public static void main(String[] arg) { // 建立三个用户 User tom = User.builder().name("Tom").age(20).build(); User kate = User.builder().name("kate").age(18).build(); User jerry = User.builder().name("Jerry").age(22).build(); // 建立链表,放入按照用户年龄升序排列的比较器 LinkedList<User> linkedList = new LinkedList<>((one, two) -> one.getT().getAge() >= two.getT().getAge()); log.info("链表初始化:{}", linkedList.toString()); linkedList.add(tom); log.info("接收到第一个用户:Tom,{}", linkedList.toString()); linkedList.add(kate); log.info("接收到第一个用户:Kate,{}", linkedList.toString()); linkedList.add(jerry); log.info("接收到第一个用户:Jerry,{}", linkedList.toString()); } }
执行以上测试样例,咱们来看下每次插入新数据后,链表结构:
经过上面结果,咱们能够看到,实时插入效果已经实现!
本篇文章经过链表结构实现了实时插入排序的功能,它的时间复杂度为O(n)
,排序执行时间,随着数据量递增。
这篇文章数据结构与我以前的一篇博文(基于队列模型编写一个入岗检查站
)是相通的,学习后,但愿对你有帮助!