面试问题:数据结构设置O(1)中的所有值

时间:2012-04-04 05:44:43

标签: data-structures

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

描述getValue(int index),setValue(int index,int value)和setAllValues(int value)都是O(1)的数据结构。

虽然数组足以让第一次和第二次操作在O(1)中执行,但第三次(setAllValues)可以提出什么呢?

18 个答案:

答案 0 :(得分:45)

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

type Entry {
  int timestamp, 
  int value
}

type structure {
    int     id
    Entry   all
    Entry[] array
}

将所有字段初始化为0.然后以下内容适用于您:

  • setValue(index i,value v):

    array[i] = {id++, value}
    
  • value getValue(index i)

    if(all.timestamp > array[i].timestamp) return all.value
    else return array[i].value
    
  • setAll(value v)

    all = {id++, value}
    

这种方法的一个问题是,最终你会用掉时间戳的id,并且可能会回滚。如果您选择64位值来存储时间戳,那么在此之前,这将为您提供18,446,744,073,709,551,616次插入或setAlls。根据数据结构的预期用途,O(n)清理阶段可能是合适的,或者您可以抛出异常。

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

  • 如果id++不是原子的,并且两个线程同时获得了新的id,那么您可以获得两个具有相同ID的条目。
  • 如果id的增量和创建的元组的赋值不是原子的(它们可能不是)并且有两个同时插入,那么你可以得到一个竞争条件,其中旧的id获胜。
  • 如果元组的赋值不是原子的,并且insert()get()同时存在{new_id, old_value}那么你最终可能会说到{{1}在数组中,导致返回错误的值。

如果这些问题中的任何一个是问题,那么绝对最简单的解决办法是在文档中使用“not thread safe”(作弊)。或者,如果您无法以您选择的语言原子地实现这些方法,则需要在它们周围放置某种同步锁。

答案 1 :(得分:6)

我在其中一次技术访谈中得到了同样的问题 这是我完整的即用型Java实现,包括测试用例。

关键的想法是将setAll()的值保留在特殊变量(例如joker)中,然后以适当的方式跟踪此值的更改。

为了保持代码清洁,一些访问修饰符已被废除。

节点 类:

import java.time.LocalDate;

class Node {

    int value;
    LocalDate jokerSetTime;

    Node(int val, LocalDate jokSetTime) {
        value = val;
        jokerSetTime = jokSetTime;
    }
}

DS 类:

class DS {

    Node[] arr;

    DS(int len) {
        arr = new Node[len];
    }
}

DataStructure 类:

import java.time.LocalDate;

class DataStructure {

    private boolean isJokerChanged;
    private Integer joker;
    private LocalDate jokerSetTime;
    private DS myDS;

    DataStructure(int len) {
        myDS = new DS(len);
    }

    Integer get(int i) {

        Integer result;

        if (myDS.arr.length < i) {
            return null;
        }

        // setAll() has been just called
        if (isJokerChanged) {
            return joker;
        }

        if (myDS.arr[i] == null) {

            // setAll() has been previously called
            if (joker != null) {
                result = joker;
            } else {
                result = null;

            }

        } else if (myDS.arr[i].jokerSetTime == jokerSetTime) {
            // cell value has been overridden after setAll() call
            result = myDS.arr[i].value;
        } else {
            result = joker;
        }

        return result;
    }

    void setAll(int val) {
        isJokerChanged = true;
        joker = val;
        jokerSetTime = LocalDate.now();
    }

    void set(int i, int val) {
        isJokerChanged = false;
        myDS.arr[i] = new Node(val, jokerSetTime);
    }
}

主要 类:

class Main {

    public static void main(String[] args) {

        DataStructure ds = new DataStructure(100);

        Integer res;

        res = ds.get(3);

        ds.set(3, 10);

        res = ds.get(3);

        ds.setAll(6);

        res = ds.get(3);

        res = ds.get(15);

        ds.set(4, 7);

        res = ds.get(4);

        res = ds.get(3);

        ds.setAll(6);

        ds.set(8, 2);

        res = ds.get(3);
    }
}

<强>更新
代码已更新。之前的实现没有考虑到setAll()连续两次调用具有相同值并且后跟set(x)get(y)的情况,例如:{{1 }},setAll(100)set(3, 1)setAll(100)set(5, 3)

添加了时间戳方法,以便区分具有相同值的不同get(3)个调用。

P.S。此实现不是线程安全的。

答案 2 :(得分:5)

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

答案 3 :(得分:3)

我刚刚在面试中被问到这个问题。我想出了一个哈希表实现。它可以解决耗尽时间戳值的问题,但需要实现线程安全功能(可能使用延迟初始化技术)

我们在课堂上说我们有一个私有变量 _defaultValue 来保存默认值,我们还有一个私有哈希表或字典 _hashtable SetAllValues 可以将 _defaultValue 设置为等于传递的值,并将 _hashtable 初始化/设置为新的哈希表,并放弃对旧哈希表的任何引用。 SetValue 应该只为 _hashtable 添加新值,或者如果 _hashtable 中已存在键(或索引),则更新该值。 GetValue 应检查 _hashtable 中是否存在键(或索引),然后返回,否则返回存储在 _defaultValue 中的值。

这是我在StackOverflow上的第一个答案。我在编写代码时有点懒惰。很可能会很快编辑答案。

面试官对此解决方案表示赞同,但坚持在不使用哈希表的情况下实施该解决方案。我想,他要我提出类似Timothy的回答。那一刻我无法得到它:(无论如何,干杯!

编辑: 发布代码(在C#中)

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;
        }
    }
}

答案 4 :(得分:2)

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

一个全局的int变量G(在SQL中就像身份一样,每当完成任何set或setAll操作时,它的值都会增加1)

初始所有Ids和V值将默认为null ..

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

答案 5 :(得分:1)

所有现有答案都使用在每setVal次操作时递增的时间戳。这不是必需的。实际上,只需要增加setAll上的时间戳。有人提出的另一个问题是算术溢出。通过更新每个setAll上的单个单元格并仔细执行时间比较,可以在不中断常数时间范围的情况下处理此问题。

如何运作

基本概念基本上与其他答案相似,但有一个转折点。

他们做什么:分别存储用于上一次setAll操作的值,并跟踪执行操作的时间。每次执行setVal时,它们都会将当前时间与给定值一起存储在数组中。每次执行getVal时,他们会将给定位置的时间与上次setAll发生的时间进行比较,然后选择位置的值或setAll值,具体取决于哪个更大。

为什么这可能是个问题:假设当前时间溢出并且很快就会发生setAll操作。当它们实际上较旧时,似乎大多数存储的数组值都比setAll值更新。

解决方案:停止想象我们正在跟踪自数据结构初始化以来已经过去的总时间。设想一个带有&#34;秒针的巨型时钟&#34;在圆圈周围不是60次,而是围绕圆圈2 ^ n次。秒针的位置表示最近setAll操作的时间。每个setVal操作都会将此时间与值一起存储。因此,如果我们在&#34;时钟&#34;时执行setAll在45,然后对不同的元素执行六次setVal操作,setAll时间和所有六个位置的时间将是相同的。我们希望保持以下不变量:

  

给定元素位置的时间等于setAll时间,当且仅当该元素的设置比最后setVal操作最近setAll时才好。

显然,上述过程会自动确保如果最近设置了元素,那么它的时间将等于setAll时间。面临的挑战是保持反向意义。

继续......

代码

我已经在Haskell中写过这个,因为这是我最熟悉的语言,但它并不是这项工作最自然的语言。

{-# LANGUAGE BangPatterns #-}
module RepArr where

import Control.Monad.Primitive
import Data.Primitive.MutVar
import qualified Data.Vector.Mutable as V
import Data.Vector.Mutable (MVector)
import Control.Applicative
import Prelude hiding (replicate)
import Control.Monad.ST
import Data.Word

-- The Int in the MutVar is the refresh pointer
data RepArr s a = RepArr (MutVar s (Word, a, Int)) (MVector s (Word,a))

-- Create a fancy array of a given length, initially filled with a given value
replicate :: (PrimMonad m, Applicative m) => Int -> a -> m (RepArr (PrimState m) a)
replicate n a = RepArr <$> newMutVar (0,a,0) <*> V.replicate n (0,a)

getVal :: PrimMonad m => RepArr (PrimState m) a -> Int -> m a
getVal (RepArr allv vec) n = do
  (vectime, vecval) <- V.read vec n
  (alltime, allval, _) <- readMutVar allv
  if (fromIntegral (alltime - vectime) :: Int) > 0
    then return allval
    else return vecval

setVal :: PrimMonad m => RepArr (PrimState m) a -> Int -> a -> m ()
setVal (RepArr allv vec) i v = do
  (!alltime, _, _) <- readMutVar allv
  V.write vec i (alltime, v)

setAll :: PrimMonad m => RepArr (PrimState m) a -> a -> m ()
setAll r@(RepArr allv vec) v = do
  (oldt, _, oldc) <- readMutVar allv
  getVal r oldc >>= setVal r oldc
  let !newc = case oldc+1 of
        op1 | op1 == V.length vec -> 0
            | otherwise -> op1
  let !newt = oldt+1
  writeMutVar allv (newt, v, newc)

为了避免潜在的(罕见的)垃圾收集暂停,实际需要取消IntWord值,以及使用未装箱的向量而不是多态向量,但是我&# 39;我的心情并不真实,这是一项相当机械的任务。

这是C中的一个版本(完全未经测试):

#include <malloc.h>

struct Pair {
  unsigned long time;
  void* val;
};

struct RepArr {
  unsigned long allT;
  void* allV;
  long count;
  long length;
  struct Pair vec[];
};

struct RepArr *replicate (long n, void* val) {
  struct RepArr *q = malloc (sizeof (struct RepArr)+n*sizeof (struct Pair));
  q->allT = 1;
  q->allV = val;
  q->count = 0;
  q->length = n;

  int i;
  for (i=0; i<n; i++) {
    struct Pair foo = {0,val};
    q->vec[i] = foo;
  }
  return q;
}


void* getVal (struct RepArr *q, long i) {
  if ((long)(q->vec[i].time - q->allT) < 0)
    return q->allV;
  else
    return q->vec[i].val;
}

void setVal (struct RepArr *q, long i, void* val) {
  q->vec[i].time = q->allT;
  q->vec[i].val = val;
}

void setAll (struct RepArr *q, void* val) {
  setVal (q, q->count, getVal (q, q->count));
  q->allV = val;
  q->allT++;
  q->count++;
  if (q->count == q->length)
    q->count = 0;
}

答案 6 :(得分:1)

/*

在我撰写本文时,此页面上的所有解决方案都会翻倍(或 更多)存储阵列所需的空间量。以下解决方案 将浪费的空间量从Ω(n)减少到θ(n / w),其中w是数量 计算机中的位“字”。在我的机器上,那是64。

这个散文在这个答案中是在C评论中,所以你可以复制并粘贴这个 逐字回答并用C编译器编译。

*/

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

/*

问题是支持在O(1)时间内在数组中读取和写入值 以及批量写入,其中数组中的所有值一次写入 O(1)时间。这可以使用Aho,Hopcroft和 据我所知,乌尔曼。我将提供一个由Gonzalo Navarro, "Constant-Time Array Initialization in Little Space"提供的版本。

这个想法是保留三个元数据数组和数据数组。我们也 保留两个整数:unset,这是批量写入中使用的最后一个值 操作,size,已经过的值的近似值 自上次批量写入后设置。在任何时候,不同值的数量 自上次批量撰写以来编写的文字介于size和w * size之间。

三个元数据数组描述了有关w值的块的信息 数据数组。他们是:

  • nth:nth [i]是自上次批量以来要写入的第i个唯一块 写

  • inverse_nth:inverse_nth [i]是其中第i个块的顺序 数组是在最后一次批量写入时从0开始计算的。

  • bitset:当数组单元编号时,bitset[i]的第j位为1 自上次批量写入以来已写入64 * i + j。

如果bitset[i]不是,则{p> inverse_nth[i]i将被视为无效 集{nth[0]nth[1],...,nth[size-1]}的成员。换一种说法, 当且仅当inverse_nth[i]时,bitset[i]inverse_nth[i] < size才有效 和nth[inverse_nth[i]] == i

我没有存储三个相同长度的独立数组,而是选择存储一个 数组,is_set,有三个字段。

*/

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);
}

/*

大部分算法都是写作和阅读元数据。后 定义IsSet()Set()(下面),读取和写入数组 简单。

*/

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;
}

/*

阅读和写作的复杂部分是双向关系 在inverse_nthnth之间。如果他们在位置i指向对方 (is_set[is_set[i].inverse_nth].nth == i)然后位置i包含有效数据 这是在最后一次批量写入后编写的,只要is_set[i].inverse_nth < size

*/

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);
}

答案 7 :(得分:0)

这是另一个python解决方案: 这是a link

from datetime import datetime
from typing import Any, Dict


class ValueNode:
    def __init__(self, value):
        self.value = value
        self.date_updated = datetime.now()

    def set_value(self, value):
        self.value = value
        self.date_updated = datetime.now()

    def get_value(self, value):
        return self.value


class Structure:
    def __init__(self):
        self._structure: Dict[Any, ValueNode] = {}
        self._set_all_node: ValueNode = None

    def get_val(self, index):
        if self._set_all_node and self._structure.get(index) and self._structure.get(index).date_updated < self._set_all_node.date_updated:
            return self._set_all_node.value
        else:
            if index in self._structure:
                return self._structure[index].value
            else:
                return None

    def set_val(self, index, value):
        self._structure[index] = ValueNode(value)

    def set_all(self, value):
        self._set_all_node = ValueNode(value)


s1 = Structure()
s1.set_val(1, 'green')
s1.set_val(5, 'blue')
s1.set_val(9, 'yellow')
print(s1.get_val(1))
print(s1.get_val(5))
print(s1.get_val('NotExistedValue'))
s1.set_all('black')
print(s1.get_val(1))
print(s1.get_val(5))
print(s1.get_val('NotExistedValue'))

答案 8 :(得分:0)

我的 Python 解决方案。测试。不是线程安全的。 如果您发现任何问题,请告诉我:)

class TimestampedNode:
    def __init__(self, timestamp, val):
        self.timestamp = timestamp
        self.val = val

class SetAllDS:
    def __init__(self):
        self.items = []
        self.timestamp = 0
        self.all_joker= TimestampedNode(self.timestamp, 0)

    def getValue(self, index):
        try:
            item=self.items[index]
        except IndexError:
            return None
        if item.timestamp<self.all_joker.timestamp:
            return self.all_joker.val
        return item.val

    def setValue(self, index, val):
        # if index<0 or index>=len(self.items): #
        #     raise IndexError("Invalid index\n")
        self.timestamp += 1
        self.items[index]=TimestampedNode(self.timestamp, val)

    def setAllValues(self, val):
        self.timestamp+=1
        self.all_joker=TimestampedNode(self.timestamp, val)

答案 9 :(得分:0)

许多解决方案都很棒,但是没有一个提到state-of-the-art一个解决方案

对于fill(v), read(i), write(i, v)操作,它具有 O(1)最坏时间复杂度
(调用 fill(v)会将数组中的所有值设置为v,并且 read / write 是不言自明的),
在阵列之外仅占用 1位额外空间。是的

因此,大小为1,000,000的int32_t数组将花费O(1)最坏的时间进行初始化(并填充),
并且仅占用32,000,001位内存。

In-Place Initializable Arrays论文中有提及,
我写过关于该主题的Article中对此有解释。

我写了一个名为Farray的C ++头文件库,该库具有 F 可操作的 Array
这是上面论文的模板实现。

答案 10 :(得分:0)

嗯,我是根据事件来做的。看看。

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;
    }
}

答案 11 :(得分:0)

我在C#中针对此问题的实现:

   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;
    }
}

陈鲁加斯

答案 12 :(得分:0)

另一个Python示例:

    class SetAll:
    def __init__(self):
        self.mapping = {}
        self.is_all_same = True
        self.all_value = None
        self.set_all_ran = False

    def set(self, index, value):
        if self.is_all_same:
            if value == self.all_value:
                return
            else:
                self.is_all_same = False
                self.mapping[index] = value
        else:
            self.mapping[index] = value

    def get(self, index):
        if self.mapping.get(index, None):
            return self.mapping[index]
        else:
            if self.is_all_same:
                return self.all_value
            else:
                if self.set_all_ran:
                    return self.all_value
        return

    def set_all(self, value):
        self.mapping = {}
        self.is_all_same = True
        self.set_all_ran = True
        self.all_value = value

答案 13 :(得分:0)

我最近也遇到了类似的问题。我使用的数据结构是哈希映射和哈希集的组合。

1)setValue(字符串键,字符串值) 在这种方法中,我直接将对插入到哈希图中。我们还将密钥插入哈希集中

2)setAllValue(字符串值) 在这种方法中,我重新初始化哈希图。这将所有配对删除,然后添加一个键,例如<“ god”>和值哈希集具有在所有版本的哈希图中维护的键集

3)getValue(字符串键) 在这种方法中,我维护多个if / else条件来返回值。

  1. 我检查条件哈希图中是否存在密钥,然后返回该密钥的值。如果尚不存在“神”键,并且每个键都保留其原始值,或者存在“神”键,但该键的值已被覆盖,则会发生这种情况。
  2. 用于检查哈希集中是否不存在该键的else / if条件,然后返回null ,因为该键从未出现在哈希图中或该映射的任何先前实例中。
  3. 最后是 else条件,其中我返回了键<“ god”> 的值,因为这意味着键已经存在于某些版本的哈希图中,并且尚未被覆盖。 li>

OptimizedMap类{

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
}

}

答案 14 :(得分:0)

这是我在Java中的答案(我不完全确定语法)。 我将set-functions同步,以避免changeT和defChangeT相等的情况。

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;
  }
}

答案 15 :(得分:0)

关于Timothy Jone的回答:

  

这种方法的一个问题是,最终你会用掉时间戳的id,并且可能会回滚。如果您选择64位值来存储时间戳,那么在此之前,这将为您提供18,446,744,073,709,551,616次插入或setAlls。根据数据结构的预期用途,O(n)清理阶段可能是合适的,或者您可以抛出异常。

这正是最糟糕的情况,这个解决方案也是O(n),而不是O(1)。这种结构虽然节省了大量潜在的O(n)插入操作,但仍处于O(n)效率。

答案 16 :(得分:0)

Python示例

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

答案 17 :(得分:-1)

C#中的正确解决方案:

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();
}