1. 程式人生 > >定時器使用佇列queue還是堆heap?

定時器使用佇列queue還是堆heap?

看需求的不同有不同的設計實現。主要的設計資料結構有三種:先進先出佇列、小頂堆、跳錶。

佇列

如果定時器任務每次插入的時候只需要插入到佇列尾部,而且沒有修改需求或只需要修改佇列尾部,那麼使用佇列的效率是最高的。插入和刪除的時間複雜度都是O(1)。
但是在大部分的業務需求都不會只需要插入到尾部,如一次插入3個任務:(1,任務執行時間7點)、(2,任務執行時間10點)、(3,任務執行時間8點)。那麼在這樣的需求下,如果使用佇列的時:

  • 新增任務的時間複雜度是O(n),因為需要遍歷整個表才能插入。由於無法估算任務最多有多少,所以無法使用陣列結構,所以無法使用二分查詢。
  • 刪除和讀取時O(1),只需要讀取和刪除隊首即可。
  • 修改任務的時間複雜度也是O(N).因為也需要遍歷表

相比佇列,使用最小隊效率是最高的:

  • 讀取的時間複雜度是O(1)
  • 刪除隊首的時間複雜度是log(n) ,需要跟新堆(時間複雜度logn)
  • 新增元素到任意位置的時間複雜度是log(n),需要跟新堆(時間複雜度logn)
  • 修改任意位置的元素的時間複雜度是log(n),需要跟新堆(時間複雜度logn)

跳錶

同樣的,也可以使用 跳錶skip list來實現。其時間複雜度和堆是一樣的。
由於redis 的sorted list是跳錶結構,在實際使用中,可以直接使用redis的sorted list來實現定時器任務。

時間複雜度對比

讀首元素 隨機增 隨機改 隨機刪除
佇列 O(1) O(N) O(N) O(N)
O(1) log(N) log(N) log(N)
跳錶 O(1) log(N) log(N) log(N)