Data structures 访谈问题:设置O(1)中所有值的数据结构
我在网上遇到了以下面试问题 描述一种数据结构,其中getValue(int-index)、setValue(int-index、int-value)和setAllValue(int-value)都是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作为
虽然数组对于在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 hashtable。
SetAllValues可以将\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;
}
}