Data structures 访谈问题:设置O(1)中所有值的数据结构

Data structures 访谈问题:设置O(1)中所有值的数据结构,data-structures,Data Structures,我在网上遇到了以下面试问题 描述一种数据结构,其中getValue(int-index)、setValue(int-index、int-value)和setAllValue(int-value)都是O(1)。 虽然数组对于在O(1)中执行的第一个和第二个操作来说已经足够好了,但是对于第三个(setAllValues)可以建议什么呢?一个元组的数组{timestamp,value},再加上一个名为all的{timestamp,value}。由于您只关心插入的相对时间,因此可以使用单调递增的id作为

我在网上遇到了以下面试问题

描述一种数据结构,其中getValue(int-index)、setValue(int-index、int-value)和setAllValue(int-value)都是O(1)。


虽然数组对于在O(1)中执行的第一个和第二个操作来说已经足够好了,但是对于第三个(setAllValues)可以建议什么呢?

一个元组的
数组
{timestamp,value},再加上一个名为
all的
{timestamp,value}
。由于您只关心插入的相对时间,因此可以使用单调递增的
id
作为时间戳的值:

type Entry {
  int timestamp, 
  int value
}

type structure {
    int     id
    Entry   all
    Entry[] array
}
将所有字段初始化为0。那么,以下几点应该对您有用:

  • 设置值(索引i,值v):

  • 值getValue(索引i)

  • setAll(值v)

这种方法的一个问题是,时间戳的ID最终会用完,并且可能会卷土重来。如果选择64位值来存储时间戳,则在发生此情况之前,将提供18446744073709551616插入或设置。根据数据结构的预期用途,O(n)清理阶段可能是合适的,或者您可以抛出异常

另一个可能需要考虑的问题是多线程。三个明显的问题:

  • 如果
    id++
    不是原子的,并且两个线程同时获得了一个新的
    id
    ,那么您可以获得两个具有相同id的条目
  • 如果id的增量和创建的元组的赋值不是原子的(它们可能不是原子的),并且有两个同时插入,那么您可能会得到一个竞赛条件,其中旧id获胜
  • 如果元组的赋值不是原子的,并且在
    get()
    的同时有一个
    insert()
    ,那么您可能会在数组中得到say
    {new\u id,old\u value}
    ,从而导致返回错误的值

如果其中有任何问题,最简单的解决方法就是在文档中添加“非线程安全”(欺骗)。或者,如果你不能用你选择的语言原子化地实现这些方法,你需要在它们周围放置一些同步锁。

一个指向单个公共值的指针数组怎么样?设置该值,所有引用都将指向O(1)中的单个更改值

class d:
    def __init__(self, l):
        self.len = l
        self.g_p = [i for i in range(self.len)]
        self.g_v = [0 for i in range(self.len)]
        self.g_s = self.len - 1
        self.g_c = 0  

    def getVal(self, i):
        if (i < 0 or i >= self.len):
            return

        if (self.g_p[i] <= self.g_s):
            return self.g_v[self.g_p[i]]

        return self.g_c

    def setVal(self, i, v):
        if (i < 0 or i >= self.len):
            return

        if (self.g_p[i] > self.g_s):
            self.g_s += 1

            self.g_p[self.g_s], self.g_p[i] = self.g_p[i], self.g_p[self.g_s]

        self.g_v[self.g_p[i]] = v

    def setAll(self, v):
        self.g_c = v
        self.g_s = -1
d类:
定义初始化(self,l):
self.len=l
self.g_p=[i代表范围内的i(self.len)]
self.g_v=[0表示范围内的i(self.len)]
self.g_s=self.len-1
self.g_c=0
def getVal(self,i):
如果(i<0或i>=self.len):
返回
如果(self.g_p[i]=self.len):
返回
如果(self.g_p[i]>self.g_s):
self.g_s+=1
self.g_p[self.g_s],self.g_p[i]=self.g_p[i],self.g_p[self.g_s]
self.g_v[self.g_p[i]]=v
def setAll(自身,v):
self.g_c=v
self.g_s=-1

我最近在一次采访中被问到这个问题。我提出了一个哈希表实现。它可以解决时间戳值用完的问题,但需要实现线程安全特性(可能使用延迟初始化技术)

假设在我们的类中,我们有一个私有变量\u defaultValue来保存默认值,我们还有一个私有哈希表或字典\u hashtableSetAllValues可以将\u defaultValue设置为等于传递的值,并将\u哈希表初始化/设置为新哈希表,并放弃对旧哈希表的任何引用设置值只需向\u哈希表添加一个新值,或者在\u哈希表中已存在键(或索引)时更新该值GetValue应检查键(或索引)是否存在于\u哈希表中,然后返回它,否则返回存储在\u defaultValue中的值

这是我关于StackOverflow的第一个答案。我写代码有点懒。可能很快就会编辑答案

采访者点头同意这个解决方案,但坚持在不使用哈希表的情况下实现它。我猜,他是在要求我给出一个与提摩西的答案类似的方法。我当时没能拿到:(。无论如何,干杯

编辑: 发布代码(用C#)

类MyDataStruct
{
私有int_defaultValue;
专用词典(hashtable);;
公共MyDataStruct()
{
_defaultValue=0;//使用某个值初始化默认值
_hashtable=新字典();
}
公共void SetAllValues(int val)
{
_defaultValue=val;
_hashtable=新字典();
}
公共void设置值(int索引,int val)
{
if(_hashtable.ContainsKey(索引))
{
_hashtable.Add(索引,val);
}
其他的
{
_哈希表[索引]=val;
}
}
公共整数GetValue(整数索引)
{
if(_hashtable.ContainsKey(索引))
{
返回_哈希表[索引];
}
其他的
{
返回_defaultValue;
}
}
}

我们可以有一个变量V,它将int和包含元组的数组存储为{Value,id}

和一个全局int变量G(它的作用类似于SQL中的identity,每当任何set或setAll操作完成时,其值都会递增1)

初始所有ID和V值将默认为空

so V = null All Tuple = {null, null}
set(index i, val v) -> G = G+1, arr[i].Val = v, arr[i].Id = G

get(index i) -> if V.Id > arr[i].Id return V.Val else return arr[i]



set-all(val v) -> G= G+1, V.Id= G, V.Val = v

关于Timothy Jone的回答:

这种方法的一个问题是,时间戳的ID最终会用完,并且可能会自动结束。如果选择64位值来存储时间戳,则会得到18446744073709551616
all = {id++, value}
class d:
    def __init__(self, l):
        self.len = l
        self.g_p = [i for i in range(self.len)]
        self.g_v = [0 for i in range(self.len)]
        self.g_s = self.len - 1
        self.g_c = 0  

    def getVal(self, i):
        if (i < 0 or i >= self.len):
            return

        if (self.g_p[i] <= self.g_s):
            return self.g_v[self.g_p[i]]

        return self.g_c

    def setVal(self, i, v):
        if (i < 0 or i >= self.len):
            return

        if (self.g_p[i] > self.g_s):
            self.g_s += 1

            self.g_p[self.g_s], self.g_p[i] = self.g_p[i], self.g_p[self.g_s]

        self.g_v[self.g_p[i]] = v

    def setAll(self, v):
        self.g_c = v
        self.g_s = -1
class MyDataStruct
{
    private int _defaultValue;
    private Dictionary<int,int> _hashtable;

    public MyDataStruct()
    {
        _defaultValue = 0; // initialize default with some value
        _hashtable = new Dictionary<int, int>();
    }

    public void SetAllValues(int val)
    {
        _defaultValue = val;
        _hashtable = new Dictionary<int, int>();
    }

    public void SetValue(int index, int val)
    {
        if (_hashtable.ContainsKey(index))
        {
            _hashtable.Add(index, val);
        }
        else
        {
            _hashtable[index] = val;
        }
    }

    public int GetValue(int index)
    {
        if (_hashtable.ContainsKey(index))
        {
            return _hashtable[index];
        }
        else
        {
            return _defaultValue;
        }
    }
}
so V = null All Tuple = {null, null}
set(index i, val v) -> G = G+1, arr[i].Val = v, arr[i].Id = G

get(index i) -> if V.Id > arr[i].Id return V.Val else return arr[i]



set-all(val v) -> G= G+1, V.Id= G, V.Val = v
/*
*/

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

/*
*/

typedef struct {
  int nth_;
  int inverse_nth_;
  uint64_t bitset_;
} IsSetCell;

typedef struct {
  int unset_;
  int size_;
  IsSetCell is_set_[];
} IsSetArray;

typedef struct {
  IsSetArray * metadata_;
  int payload_[];
} ResettableArray;

/*
*/

ResettableArray * ConstructResettableArray(int n, int unset) {
  ResettableArray* result =
      malloc(offsetof(ResettableArray, payload_) + n * sizeof(int));
  if (!result) return NULL;
  n = (n + 63) / 64;
  result->metadata_ =
      malloc(offsetof(IsSetArray, is_set_) + n * sizeof(IsSetCell));
  if (!result->metadata_) {
    free(result);
    return NULL;
  }
  result->metadata_->size_ = 0;
  result->metadata_->unset_ = unset;
  return result;
}

void DestructResettableArray(ResettableArray * a) {
  if (a) free(a->metadata_);
  free(a);
}

/*
*/

bool IsSet(const IsSetArray * a, int i);
void Set(IsSetArray * a, int i);

int GetValue(const ResettableArray * a, int i) {
  if (!IsSet(a->metadata_, i)) return a->metadata_->unset_;
  return a->payload_[i];
}

void SetValue(ResettableArray * a, int i, int v) {
  a->payload_[i] = v;
  Set(a->metadata_, i);
}

void SetAllValues(ResettableArray * a, int v) {
  a->metadata_->unset_ = v;
}

/*
*/

uint64_t OneBit(int i) {
  return UINT64_C(1) << i;
}

bool IsSet(const IsSetArray * a, int i) {
  const int cell = i/64, offset = i & 63;
  const int inverse_nth = a->is_set_[cell].inverse_nth_;
  return inverse_nth < a->size_ && a->is_set_[inverse_nth].nth_ == cell &&
         a->is_set_[cell].bitset_ & OneBit(offset);
}

void Set(IsSetArray * a, int i) {
  const int cell = i/64, offset = i & 63;
  const int inverse_nth = a->is_set_[cell].inverse_nth_;
  if (inverse_nth >= a->size_ || a->is_set_[inverse_nth].nth_ != cell) {
    a->is_set_[cell].inverse_nth_ = a->size_;
    a->is_set_[cell].bitset_ = 0;
    a->is_set_[a->size_].nth_ = cell;
    ++a->size_;
  }
  a->is_set_[cell].bitset_ |= OneBit(offset);
}
public sealed class SpecialDictionary<T, V>
{
    private Dictionary<T, Tuple<DateTime, V>> innerData;
    private Tuple<DateTime, V> setAllValue;
    private DateTime prevTime;

    public SpecialDictionary()
    {
        innerData = new Dictionary<T, Tuple<DateTime, V>>();
    }
    public void Set(T key, V value) => innerData[key] = new Tuple<DateTime, V>(GetTime(), value);
    public void SetAll(V value) => setAllValue = new Tuple<DateTime, V>(GetTime(), value);
    public V Get(T key)
    {
        Tuple<DateTime, V> tmpValue = innerData[key];
        if (setAllValue?.Item1 > tmpValue.Item1)
        {
            return setAllValue.Item2;
        }
        else
        {
            return tmpValue.Item2;
        }
    }
    private DateTime GetTime()
    {
        if (prevTime == null)
        {
            prevTime = DateTime.Now;

        }
        else
        {
            if (prevTime == DateTime.Now)
            {
                Thread.Sleep(1);
            }
            prevTime = DateTime.Now;
        }
        return prevTime;
    }
}
static void Main(string[] args)
{
    SpecialDictionary<string, int> dict = new SpecialDictionary<string, int>();
    dict.Set("testA", 1);
    dict.Set("testB", 2);
    dict.Set("testC", 3);
    Console.WriteLine(dict.Get("testC"));
    dict.SetAll(4);
    dict.Set("testE", 5);
    Console.WriteLine(dict.Get("testC"));
    Console.WriteLine(dict.Get("testE"));
    Console.ReadKey();
}
Struct ValueSt{ 
  int value;
  Timestamp changeT;
}

Class MyDS{
  int default;
  Timestamp defChangeT;
  HashMap map;

  public MyDS(){
    map = new HashMap<int, ValueSt>();
  }

  public synchronized void mySet(Int key, int value){
    ValueSt vs = new ValueSt(value, Timestamp(System.current));
    map.put(key, vs);
  }

  public synchronized void setAll(int value){
    default = value;
    defChangeT = Timestamp(System.current));
  }

  public int myGet(int key){
    ValueSt vs = map.get(key);
    if(vs != null){
      if(vs.changeT > defChangeT)
        return vs.value;
      else
        return default;
    }
    return null;
  }
}
Map<String, String> mymap = new HashMap<String>();
Set<String> myset = new HashSet<>();
public void setValue (String key, String value) {
    mymap.put(key, value);
    myset.add(key);
}

public void setAllValue (String value) {
    mymap = new HashMap<>();
    mymap.put("god", value);
}

public String getValue (String key) {
    if (mymap.containsKey(key)) {
        return mymap.get(key);
    } else if (!myset.contains(key)) {
        return null;
    } else {
        return mymap.get(key);
    }
}

public static void main (String args[]) {

    OptimisedMap opmap = new OptimisedMap();
    String value = opmap.getValue("hey");
    if (value == null) {
        System.out.println("Key not present");
    }
    opmap.setValue("hey", "there");
    opmap.setValue("ho", "there");
    System.out.println(opmap.getValue("hey")); // will print there
    opmap.setAllValue("whatsup");
    System.out.println(opmap.getValue("hey")); // will print whatsup
    System.out.println(opmap.getValue("ho")); // will print whatsup
    opmap.setValue("hey", "there");
    System.out.println(opmap.getValue("hey")); // will print there
    System.out.println(opmap.getValue("ho")); // will print whatsup
}
   public class MyStruct
    {
    public MyStruct(int val)
    {
        this.value = val;
        this.currentTime = 0;
    }
    public int value { get; set; }
    public int currentTime { get; set; }
}

public class Struct
{
    public List<MyStruct> array = new List<MyStruct>();
    public MyStruct all = new MyStruct(0);

    public int GetValue(int index)
    {
        if(all.currentTime >= array[index].currentTime)
        {
            return all.value;
        }
        else
        {
            return array[index].value;
        }
    }

    public void Set(int index, int value)
    {
        if(array.Count <= index)
        {
            array.Add(new MyStruct(value));
        }
        else
        {
            array[index].value = value;
        }
        array[index].currentTime = all.currentTime +1;
    }

    public void SetAll(int value)
    {
        all.value = value;
        all.currentTime++;
    }

    public void Delete(int index)
    {
        array[index].currentTime = 0;
        array[index].value = -1;
    }
}
internal class Program
{
    public static void Main(string[] args)
    {
        SomeUsefullDataStructure ds = new SomeUsefullDataStructure();
        
        ds.SetValue(1, "11");
        ds.SetValue(2, "22");
        var result = ds.GetValue(2);
        ds.SetAllValues("haha");

        Console.ReadKey();
    }
}

public class SomeUsefullDataStructure
{
    private delegate void SetValueDelegate(string newValue);
    private event SetValueDelegate SetValueEventFired;
    private Dictionary<int, StringDataEntry> dict = new Dictionary<int, StringDataEntry>();

    public string GetValue(int key)
    {
        if (dict.ContainsKey(key))
        {
            return dict[key].StringValue;
        }
        
        throw new ArgumentException("no such key");
    }

    public void SetValue(int key, string value)
    {
        if (dict.ContainsKey(key))
        {
            dict[key].UpdateValue(value);
        }
        else
        {
            StringDataEntry stringDataEntry = new StringDataEntry(value);
            SetValueEventFired += stringDataEntry.UpdateValue;
            dict.Add(key, stringDataEntry);
        }
    }

    public void SetAllValues(string value)
    {
        SetValueEventFired(value);
    }
}

public class StringDataEntry
{
    public string StringValue { get; private set; }

    public StringDataEntry(string value)
    {
        StringValue = value;
    }
    
    public void UpdateValue(string newValue)
    {
        StringValue = newValue;
    }
}