It really depends on what other constraints you have, e.g.:
- Do you need to maintain the order in which the number come in?
- Are the numbers are only ever added, or are they deleted too?
- What is a more common operation: add/delete or check for dupes?
- What do you need to keep - the set (i.e., unique numbers) or the multiset (numbers with their multiplicities)?
The former will give you O(log(n))
operations on average, the latter - O(1)
; the actual results will depend on what kind of stream you have (are the numbers random? increasing? follow a weird non-obvious pattern?)
If you decide to go for BST, remember that you will have to keep it balanced.
Example (untested)
(defparameter *my-data-array* (make-array 100000))
;; fill *my-data-array*
(defparameter *my-data-table*
(let ((ht (make-hash-table)))
(loop for v across *my-data-array*
do (incf (gethash v *my-data-table* 0)))
ht))
(defun modify-data-array (pos new-value)
(let* ((old-value (aref *my-data-array* pos))
(old-count (decf (gethash old-value *my-data-table*)))
(new-count (incf (gethash new-value *my-data-table* 0))))
(setf (aref *my-data-array* pos) new-value)
(case old-count
(0 ; old-value is now not in the array
...)
(1 ; old-value is now unique
...)
(t ; old-value is still not unique
...))
(case new-count
(1 ; new-value was not in the array before
...)
(2 ; new-value was unique before, but not anymore
...)
(t ; new-value was not unique
...))))