0

I need to frequently add and remove elements to and from a large number of sorted lists.

The lists are bound in size, and relatively small -- around 100 elements or less, with each element being on the order of 32 bytes or thereabouts.

If inserting into a full list, the last element can be discarded.

I've done some simple profiling, and found that storing these lists in arrays and using memmove to move everything after the insertion point backwards works surprisingly well; better even than using a linked list of a fixed size and linking the tail into the insertion point. (Never underestimate the power of spatial locality, I guess.)

But I think I can do even better. I suspect that most of my operations will be near the top of the lists; that means I'm going to memmove the vast majority of the list every time I insert or remove. So what if I were to implement this as a sort of ring buffer, and if an operation is closer to the top than the bottom, I shift the topmost items backwards, with the old tail getting overwritten by the head? This should theoretically involve cheaper calls to memmove.

But I'm completely brain farting on implementing this elegantly. The list can now wrap around, with the head being at position k and the tail being at position (k-1)%n if the list is full. So there's the possibility of doing three operations (k is the head, m is the insertion point, n is the max list size).

  1. memmove elements k through n-1 back one
  2. memcpy element 0 to location n-1
  3. memmove elements 1 through m-1 back one

I don't know if that'll be faster than one bigger memmove, but we'll see.

Anyway, I just have a gut feeling that there's a very clever and clean way to implement this through modulo arithmetic and ternary operators. But I can't think of a way to do this without multiple nested "if" statements.

  • If we're inserting or removing.
  • If we're closer to the front or the back.
  • If the list "wraps around" the end of the array.
  • If the item being inserted is in the same segment as the head, or if it needs to go in the wrapped around portion.
  • If the head is at element 0.

I'm sure that too much branching will doom any improvements I make with smaller memmoves. Is there a clean solution here that I just am not seeing?

user1274193
  • 1,104
  • 1
  • 10
  • 11
  • 1
    Are you finding the insertion point with binary search? – Gene Jan 18 '14 at 21:59
  • @Gene: Currently linear, due to the front-of-the-list bias. – user1274193 Jan 18 '14 at 22:08
  • @user1274193 I don't get that comment. If the list is ascending and you are inserting from the rear then "front of the list" means linear is wrong. Showing your code or at least algorithm as pseudocode would be helpful. Additionally, if you store the arrays in reverse order the bias will work for you. – Gene Jan 18 '14 at 22:14
  • @Gene: The list is descending from index 0. I start the search at index 0 and proceed linearly because I expect most of the "action" to involve the bigger items. My problem is that if I find an insertion point at index 5, I have to shift the next 94 items downwards. I can't merely shift 5 items upwards, because then the biggest item would have nowhere to go -- except wrap around to index 99, and now you have the ring structure I'm describing in my question. – user1274193 Jan 18 '14 at 22:53

0 Answers0