불변 상태로 객체 그래프의 변이를 효과적으로 표현할 수 있습니까? 사본이 필요하지만 허용되지 않았습니다. 변경되지 않은 노드를 공유하려고했습니다.

C ++에서 불변 객체 사용을 연습하고 있습니다. 내 개인적인 목표는 불변의 그래프 시퀀스로 일반 객체 그래프 (힙)를 나타내는 것입니다.

다중 버전 그래프 자체를 만드는 것은 그리 어렵지 않습니다. 문제는 성능입니다. 무차별 버전 관리에는 전체 그래프 사본이 필요하지만 허용되지 않았습니다.

변경되지 않은 노드를 공유하려고했습니다. 그러나이 경우 새로운 문제가 생겼습니다. 참조. 다른 객체에 대한 참조는 전체 그래프에서 업데이트해야합니다. 새 그래프 버전을 파생시킬 때마다 모든 노드를 방문해야합니다. 그리고 이것은 참조로 노드를 변경하므로 (복사) 파생되어야합니다. 무차별 복사보다 성능이 향상되지 않습니다.

내가 상상할 수있는 한, 불변 상태로 객체 그래프의 변이를 표현하는 효과적인 방법은 없습니다. 그래서 이것에 대한 아이디어를 요구하고 있습니다.

불변 상태에서 객체 그래프의 변이를 효율적으로 표현할 수 있습니까?



답변

찾고있는 것을 영구 데이터 구조 라고합니다 . 영구적 인 데이터 구조를위한 표준 자원은 Chris Okasaki의 Book Purely Functional Data Structures 입니다. 영구 데이터 구조는 Clojure와 Scala로 대중화되어 최근에 관심을 모았습니다.

그러나 이상한 이유로 인해 영구 그래프는 대부분 무시되는 것으로 보입니다. 우리는리스트, 수십 가지 종류의 트리, 배열, 우선 순위 큐, 맵을 가지고 있지만 그래프는 없습니다.

나는 완전히 하나의 종이를 찾았습니다 : 완전 지속 그래프 – 어느 것을 선택해야합니까?


답변

객체 간 연결을 버전이 지정된 리소스의 일부로 간주하지 않으면 (다음 경우에는 큰 도움이되지 않을 수 있음) 연결 부분을 나타내는 부분으로 객체를 분할하는 것을 고려할 수 있습니다. 객체와 불변 상태를 나타내는 부분.

그런 다음 각 연결 하위 오브젝트에 버전이 지정된 상태의 벡터가 포함되도록 할 수 있습니다. 이런 식으로 그래프 버전 번호로 조작하여 적절한 불변 상태에 액세스 할 수 있습니다.

특정 노드에 대한 업데이트가있을 때마다 전체 그래프를 가로 지르지 않기 위해 노드의 현재 버전 번호보다 큰 버전 번호로 노드에 액세스 할 경우 현재 버전이 사용되도록 그래프를 만들 수 있습니다 . 그런 다음 노드가 업데이트되면 모든 중간 버전을 이전 버전으로 채우므로 객체 그래프에 대한 지연 업데이트를 수행 할 수 있습니다.

객체 간 연결이 버전 화 된 상태의 일부인 경우 위의 내용이 작동하지 않습니다. 그러나 다음과 같이 확장 할 수 있습니다.

그래프의 각 개체에 대해 “핸들 개체”를 만듭니다. 핸들 객체는 버전이 변경되지 않은 상태 목록을 포함합니다. 그래프의 객체에 객체 참조를 저장하는 대신 핸들 객체에 대한 참조를 저장합니다. 그런 다음 현재 처리되고있는 오브젝트 그래프의 핸들과 버전보기를 사용하여 핸들을 통해 오브젝트에 대한 각 참조를 역 참조합니다. 이것은 객체에 대한 올바른 불변 상태를 반환합니다. 불변 상태는 핸들을 사용하여 그래프의 다른 객체를 참조하므로 항상 처리하려는 그래프 버전의 일관된 날짜를 얻습니다.

위에서 설명한 것과 동일한 논리가 핸들 내에서 버전을 업데이트 할 때 적용되며, 지연된 로컬 업데이트가 가능합니다.


답변

이 문제에 대한 상각 시간 복잡성이 매우 우수한 게시 된 솔루션이 있지만, 무엇을 찾아야할지 정확히 알지 못하는 경우 찾기가 어렵습니다. 이 강의 노트 (2.2.3 단원 확인) 에서 훌륭한 요약을 찾 거나 원본 데이터 작성 영구 문서를 읽으십시오 . 객체 그래프의 연결성이 제한적인 경우 (예 : 트리와 같은 구조) 불변 그래프를 읽고 업데이트하는 데있어 상각 된 O (1) 복잡성에 도달 할 수도 있습니다.

아이디어는 각 객체는 현재의 불변 상태를 저장하는 것 외에 변경 사항을 기록 할 공간을 확보한다는 것입니다. 변경 사항을 적용하여 기존 그래프에서 변경 불가능한 새 그래프를 만들려면 두 가지 경우를 고려해야합니다.

  • 변경하려는 객체에는 여전히 변경을위한 공간이 있습니다. 변경 사항을 오브젝트에 직접 저장할 수 있습니다.

  • 개체에 더 이상 변경할 공간이 없습니다. 현재 값과 빈 변경 레코드를 기반으로 새 인스턴스를 만듭니다. 이제 이전 객체를 참조하는 모든 객체를 재귀 적으로 업데이트하여 새 객체를 참조해야합니다.

    참조 객체 자체에 여전히 변경을위한 공간이있는 경우 변경 사항을 참조에 직접 저장할 수 있습니다.

이 체계는 새로운 세대의 불변 객체 그래프의 효율적인 생성을 지원하지만, 불변 객체에서 데이터를 읽을 때 액세스하려는 “버전”을 지정해야하므로 읽기가 복잡합니다. 저장된 변경 레코드로 인해 변경 불가능한 오브젝트에 여러 버전에 대한 정보가있을 수 있으므로 보려는 버전을 지정해야합니다.

이것을 구현할 때 API 에서이 복잡성을 숨기려고합니다. 외부에서 불변 그래프에서 무언가를 참조 할 때 직접 참조 대신 생성 된 스텁을 사용하므로 호출자는 원하는 버전을 수동으로 계속 전달 할 필요가 없습니다. 이렇게하면 참조가 직접 포인터보다 약간 비싸지 만 편의 가치가 있다고 생각합니다.


답변