"Adaptive indexing" search
"Adaptive indexing" search
Some kind of interpolation search. We take the first item and test it. If hit - return it, otherwise - shift to the next item by a step. The step is calculated from the current item value and the previous one's value: the idea is that we try to find the delta/difference between neighbor items and to calculate the offset to the searched item. It's something like adaptive indexing, I called it in such a way.
It works good with integers without "gaps". But if we have "gaps" - the data access numbers is bigger. It depends on how random are items. The function partiallyrandomdata() has a parameter rate which can be used to simulate less or more randomization (0 - no "gaps", 1.0 - a lot of).
If the test fails - we move forward/backward by a step. If we hit bounds then we correct the step - we take the next item after the previous one if it's possible, otherwise - the previous of the previous (_prev +/-1).
This implementation is not perfect and can be optimized. I am not 100% sure in its correctness even, but some tests show that the item was successfully found. ''Also it loops infinitely if not such item at all''.
import random from math import * # lst - ordered/sorted list def intersearch(lst, target): upbound = len(lst) - 1 prev = -1 pos = 0 step = 1 _prev = None d = 0 while True: pos_el = lst[pos] if pos_el == target: return pos elif prev != -1: d = abs(pos_el - lst[prev]) if d == 0: step = 1 else: step = (target - pos_el) // d if step == 0: step = 1 elif step < 0: #elif (pos + step) < 0: step = 1 else: step = 1 ### if (pos + step > upbound) or (lst[pos + step] > target): if prev + 1 > upbound: _prev = prev prev = pos pos = _prev - 1 else: _prev = prev prev = pos pos = _prev + 1 else: prev = pos pos += step ######################### class ACCESS(list): def __init__(self, *a, **kw): super().__init__(*a, **kw) self._access = 0 def __getitem__(self, i): if i >= len(self): print(f"{self._access}: [{i}]=OUT OF RANGE!") res = super().__getitem__(i) print(f"{self._access}: [{i}]={res}") self._access += 1 return res def randomdata(num): i = 0 res = [] while i < num: r = random.randint(0, num*10) res.append(r) i += 1 res = sorted(res) return (res, random.choice(res)) def partiallyrandomdata(num, ratio=0.5): res = list(range(NUM)) i = 0 cnt = min(num, num*ratio) while i < cnt: r = random.randint(num, num+cnt-1) res[r - num] = r i += 1 res = sorted(res) return (res, random.choice(res)) NUM = 10000 arr, x = partiallyrandomdata(NUM, 0.5) print(f"Look for {x} in {arr}") try: fnd = intersearch(ACCESS(arr), x) #fnd = intersearch(arr, x) print(f"Found {arr[fnd]} at {fnd}") except KeyboardInterrupt: print(f"Looked for {x} in {arr}")