在正常的工做中,咱們常常遇到從消息隊列中接收一天的數據量,並對其進行排序的場景。那麼,咱們一般會想到最經典的十大經典排序算法
。確實,這些算法均可以知足咱們的場景須要,,但若是咱們要求接收消息過程當中,實時進行排序呢?這些算法顯然都不能知足需求,它們都是在接收到全部數據後,再統一排序。因此,今天,咱們動手本身遍寫一個實時插入排序算法!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)
,排序執行時間,隨着數據量遞增。
這篇文章數據結構與我以前的一篇博文(基於隊列模型編寫一個入崗檢查站
)是相通的,學習後,但願對你有幫助!