벡터 /리스트는 언제 사용해야합니까?


17

목록을 언제 사용해야하는지 이해할 수는 있지만 비디오 게임에서 목록을 사용하는 것보다 벡터를 사용하는 것이 더 좋은시기를 이해하지 못합니다.

(포인터를 제거 / 추가하기 때문에 목록에 삽입 / 삭제하는 것이 더 빠른 이유를 이해하지만 여전히 해당 항목을 찾아야합니다 ...)


벡터 태그를 여기에 다시 추가-목록이 유효한 태그이면 벡터도 추가됩니다.
Kylotan

아마도 벡터는 std :: vector가 아닌 수학적 벡터를 의미하기 때문에 제거되었습니다.

1
어떻게 둘 다 nix하고 넣습니다 container.
deft_code

@Kylotan : Joe가 말한대로입니다. 이 질문은 확실히 벡터에 관한 것이지만 벡터 태그에는 속하지 않았습니다.
doppelgreener

1
모호한 태그를 제거합니까? 그것은 나에게 잘못된 결정처럼 들립니다. 당신의 검색이 충분하지 않은 것보다 많은 정보를 얻는 것이 좋습니다. 원하지 않는 결과를 건너 뛰는 것은 동의어를 찾기 위해 브레인 스토밍하는 것보다 쉽습니다.
Kylotan

답변:


29

내 엄지 손가락의 규칙, 그리고 나는 확실히 이것에 대한 논의가있을 것이야,하는 것입니다 결코 목록을 사용하지 않습니다 (당신은 매우, 매우 자주 큰 목록의 중간에서 사물을 제거 할 필요가없는 경우).

컨테이너의 모든 요소를 ​​연속 메모리 (따라서 캐시 친화적)로 유지함으로써 얻을 수있는 속도는 벡터를 추가 / 제거 / 크기 조정하는 추가 비용을 상쇄 할 가치가 있습니다.

편집 : 조금 더 명확히하기 위해, 물론 어떤 종류의 "더 빠른"질문은 특정 요구 사항과 관련된 모든 데이터 세트가있는 플랫폼에서 테스트되어야한다는 것은 말할 필요도 없습니다. 요소 컬렉션이 필요한 경우에는 합당한 이유가 없는 한 벡터 (또는 거의 동일한 것 인 deque) 를 사용하십시오.


1
특정 요소에 액세스 할 필요가 없으며 모든 요소를 ​​읽을 필요가 있고 요소를 자주 추가하고 제거 해야하는 경우 목록이 더 나은 솔루션입니다.
Frédérick Imbeault

11
@ 프레데릭 : 이것이 표준 C ++의 지혜이지만, 거의 항상 잘못되었습니다. 벡터, 특히 포인터 벡터를 다룰 때 (거의 항상 게임에 사용되는), 중간에서 물건을 제거하는 것이 매우 빠릅니다. 선형 시간이지만 항목 당 매우 작은 오버 헤드입니다. 또한의 많은 순차적으로 벡터를 통해 빠르게 반복.

1
정확히 어떤 종류의 구조를 얻었는지 잘 모르겠습니다. 이러한 최적화에는 확실한 예를 들어 구체적인 예가 필요합니다. 예를 들어, 유스 케이스에 대한 나의 첫 반응은 정렬되지 않은 세트 일 것입니다. 내 경험에 따르면 세트는 편집기의 객체에 좋습니다. 그러나 편집자들은 많은 실시간 실시간 성능 요구 사항을 가지고 있습니다. 예를 들어 "삭제"버튼을 누르는 것에 응답하는 데 1/20 초가 걸리거나 10 분의 1 초가 1 / 2 % 걸리는 경우에 좋습니다 –이 수준의 최적화 그들에게는 거의 적용되지 않습니다.

1
@ Frédérick Imbeault Modified는 문제를 일으키지 않는 Add \ Remove라는 문제가 아닙니다. 추가 / 제거 지점에서 벡터의 끝까지 벡터가 연속되어 유지되도록 복사됩니다. 요소 순서가 중요하지 않으면 삭제 된 요소를 마지막 요소와 교체 한 다음 삭제를 위해 팝하고 추가를 위해 끝에 추가하십시오.
stonemetal

4
벡터에서 요소의 주소를 가져 와서 저장하는 것은 안전하지 않습니다. 그러나 일반적으로 말하기는 거의 불가능합니다. 대신 요소 포인터로 구성된 벡터를 사용하고 포인터를 주변에 복사하는 것을 선호합니다 (또는 유사한 것).
Tetrad

8

데이터 구조의 중간을 수정하여 반복자 무효화로 인해 문제가 발생하거나 빠른 중간 콜렉션 삭제를위한 스왑 및 팝 트릭이 작동하지 않고 요소를 정렬해야하는 경우 목록을 사용하십시오. 중간 컬렉션 삭제 횟수

Deque 사용을 고려할 수도 있습니다. 벡터와 비슷한 성능 특성을 가지고 있지만 벡터가 연속 메모리를 필요로하지 않으며 약간 더 유연합니다.


deques를 언급 한 유일한 사람이 +1-벡터의 연속적인 메모리 및 조회 속도 이점을 얻을 수 있으며 양쪽 끝에 빠른 삽입 / 제거 기능이 있습니다.

5

당신의 선택은 당신의 필요를 반영해야합니다. 벡터의 모든 요소는 메모리에 연속적이며 목록에는 다음 / 이전 요소에 대한 포인터가 있으므로 각각의 장점 / disavantages가 있습니다.

리스트 :

  • 각 요소는 2 개의 정수를 사용하여 이전 및 다음 요소를 가리 키므로 가장 일반적으로 목록의 각 요소에 대해 8 바이트 더 큽니다.
  • 시간에 따른 선형 삽입 : O (n)
  • 제거는 일정한 작업입니다. O (1)
  • x 요소가 시간에 선형 인 액세스 : O (n)

벡터 :

  • 적은 메모리가 필요합니다 (다른 요소에 대한 포인터는 없으며 간단한 수학 알고리즘입니다)
  • 제거는 시간에 선형입니다 : O (n)
  • x 요소는 상수에 액세스 : O (1) (요소가 메모리에 연속적이므로 간단한 수학 연산 vectorPtr + (x * bytesOfTheType)이므로)
  • 삽입은 선형 시간이 될 수 있지만 가장 일반적으로 상수 연산입니다 : O (1)

따라서 프로그램에서 요소를 자주 추가하고 제거해야하지만 이전에 다른 요소가 없어도 특정 요소에 액세스하거나 거의 액세스하지 않는 경우 목록이 더 좋습니다. 벡터는 더 나은 액세스 시간을 위해 사용해야하지만 요소를 제거하거나 추가해야 할 때 효율성이 떨어집니다.

stackoverflow 에서이 게시물을 확인하면 답변에 따라 특정 컨테이너로 안내하는 요구 사항에 대한 기본적인 질문이있는 멋진 그래프가 표시됩니다.

/programming/366432/extending-stdlist


3
이 그래프는 실제로 "포인터를 저장하고 있고 천 개 미만입니까? 아니오-> 벡터"노드로 시작해야합니다.

예, 아마도 당신이 옳을 수도 있습니다. 저장 된 유형도 고려하지 않았으며 분석해야합니다.
Frédérick Imbeault

2

일반적으로리스트는 추가 및 제거 조작이 많은 큐와 같은 구조에 사용됩니다. 예 : 끊임없이 변경되어야하는 엔티티 목록. 목록 자체에는 화면의 엔터티 만 포함되므로 자주 변경됩니다.

벡터 (또는 배열)는 그다지 변경되지 않고 컬렉션 내의 개별 항목에 빠르게 액세스해야하는 컬렉션에 더 적합합니다. 예 : 주어진 인덱스에서 타일을 찾아야하는 타일 맵.

Tetrads의 의견은 사실 일 수 있지만 사용되는 프로그래밍 언어에 따라 다릅니다. 귀하가 귀하의 질문에 태그를 추가 한 c++것을 보았지만 언어별로 다른 답변을 주려고했습니다.


글쎄, C를 넣었을 수도 있지만 C에는 그러한 컨테이너가 없지만 생각해 볼 점은 다음과 같습니다 .C에 대한 STL과 같은 tibrary가 있습니까?
jokoon

나는 과거에 glib ( library.gnome.org/devel/glib )를 사용했는데 , C에 대한 많은 표준 데이터 구조를 구현합니다. 보통 너무 장황하고 필사적으로 C ++이되기를 원하기 때문에 싫어했습니다. 안정된.

0

콘솔 게임에서는 다음과 같은 이유로 std :: list를 사용하지 않습니다.

  1. 새 항목을 추가 할 때마다 메모리 할당을 수행합니다. 메모리 할당이 느립니다.
  2. 포인터로 가득합니다. 포인터가 잘못되었습니다. 포인터는 캐시 미스입니다. 캐시 미스가 나쁘다.

std :: vector조차도 콘솔에서 호의를 잃고 있습니다.

  1. 예를 들어 모든 객체의 위치에만 관심이있는 경우가 많습니다. 예를 들어 객체를 서로 충돌 시키려면 색상이 무엇인지 상관하지 않습니다. 캐시의 오염을 피하기 위해 모든 위치가 메모리에서 연속적이기를 원하고 색상을 다른 곳에 배치하려고합니다. 그러나 std :: vector는 각 객체에 대한 모든 것을 인접한 메모리 덩어리 (예 : 위치 및 색상)에 저장해야하므로 위치 만 읽는 작업을 수행하는 경우 모든 색상을 캐시로 읽어야합니다. 당신이 그들을 사용하지 않으면. 이것은 낭비입니다.

5
@bmcnett "[] .. 그러나 std :: vector는 각 객체에 대한 모든 것을 인접한 메모리 덩어리에 저장해야합니다."-컨테이너의 문제가 아니라 데이터 레이아웃의 문제입니다. 모든 위치를 가질 수 있습니다. : 성병 : 벡터와 메모리의 연속 덩어리에struct point{float x, y, z, w}; std::vector<point> positions;
Maik Semder

우리 학교는 이것을 좋아할 것입니다 :)
jokoon

2
-1이 답변은 이미 여기에있는 목록과 벡터 토론에 아무것도 추가하지 않으며 Maik가 말한 것처럼 캐시를 오염시키는 벡터에 대한 주장은 잘못 되었기 때문입니다.

당신은 내 주장을 오해했습니다. 나는 모든 컨테이너 중 std :: vector가 캐시를 오염시키는 것이 유죄 라고 결코 말하지 않았습니다 . 모든 컨테이너들, 심지어는 심지어 배열까지도 똑같이 유죄입니다. C ++ 객체 자체 가 선호하지 않기 때문에 std :: vector가 선호되지 않습니다. C ++에서는 각 객체의 데이터가 메모리에서 연속적이어야합니다. C ++ 객체를 피함으로써 예를 들어 위에서 언급 한 std :: vector <position>을 사용하여 해결할 수 있습니다.
bmcnett

3
pointC ++ 객체는 예외 입니다 (있는 std::vector그대로 float). 나는 당신이 그리려고하는 구별을 알고 있지만 당신은 그것을 설명하는 나쁜 일을하고 있습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.