C++ - 목록 소개 및 목록의 시뮬레이션 구현

목록 소개

 list는 상수 범위 내의 모든 위치에서 삽입 및 삭제를 지원하는 순차 컨테이너이며 이 컨테이너는 앞뒤로 반복될 수 있습니다. 목록은 양방향 순환 연결 목록의 구조로 이해할 수 있습니다.

다른 구조화된 컨테이너와 비교할 때 목록 삽입 및 모든 위치에서의 기능 효율성이 훨씬 높으며 목록의 단점도 명백하여 컨테이너의 데이터에 임의로 액세스할 때 알려진 위치에서 선형으로만 시작할 수 있습니다 검색, 이 검색은 다른 컨테이너에 비해 시간이 많이 걸리고 스토리지 측면에서 각 노드가 별도로 저장되기 때문에 각 노드 간의 관계를 저장하기 위해 더 많은 공간이 열리고 소비도 더 높습니다.

 목록 사용

 건설자

생성자 ( (생성자)) 인터페이스 설명
목록 (size_type n, const value_type& val = value_type()) 생성된 목록에는 값이 val인 n개의 요소가 포함되어 있습니다.
목록() 빈 목록 구성
목록(상수 목록& x) 복사 생성자
목록(InputIterator 먼저, InputIterator 마지막) [첫 번째, 마지막) 범위의 요소로 목록을 구성합니다.

리스트의 생성자는 문자열과 벡터와 유사하며 자세한 내용은 다음 블로그를 참조하십시오.

C++ 문자열 클래스 반복자 범위 for_c++string iterator_chihiro1122의 블로그-CSDN 블로그

 반복자

 목록의 반복자는 더 이상  문자열 및 벡터와 같은 원시 포인터를 

함수 선언 인터페이스 설명
시작 +
첫 번째 요소에 대한 반복자를 반환하고 + 마지막 요소의 다음 위치에 대한 반복자를 반환합니다.
rbegin +
렌드
끝 위치인 첫 번째 요소의 reverse_iterator를 반환하고 시작 위치 인 마지막 요소의 다음 위치의
reverse_iterator를 반환합니다.

 참고 :

  • 리스트의 저장 구조가 문자열의 저장 구조와 다르기 때문에 문자열의 저장 구조는 연속적인 간격이므로 문자열 클래스의 이터레이터는 str.begin() + 5와 같은 연산을 지원하지만 리스트이기 때문에 불연속 공백이고 연산자 "+"의 비용이 문자열의 비용보다 높기 때문에 operator+ 함수는 목록의 반복자에서 구현되지 않습니다! !
  • 반복자의 사용에 대해 "<" 형식은 반복자의 범위를 판단하는 데 사용할 수 없습니다! ! 목록의 각 노드의 저장 공간이 연속적이지 않기 때문에 직접 "<"를 사용하여 비교하면 포인터 저장의 주소 크기가 비교되므로 큰 문제가 발생합니다.반복자의 사용은 일반적으로 다음과 같습니다. :
list<int> L( 10 , 1 );
list::iterator it = L.begin();

while(it != L.end())
{
    cout << *it << " ";
    ++it;
}
cout << endl;

 기타 기본 작업

 STL에서 이들 함수는 기본적으로 같은 방식으로 사용되며 이전에 문자열과 벡터를 소개한 블로그를 참조할 수 있습니다.

C++ 문자열 클래스 반복자 범위 for_c++string iterator_chihiro1122의 블로그-CSDN 블로그

C++ string class-2_chihiro1122의 블로그-CSDN 블로그

C++ - 벡터 클래스 반복자 무효화에 대한 최초 지식 - chihiro1122의 블로그 - CSDN 블로그

목록 용량

함수 선언 인터페이스 설명
비어 있는 목록이 비어 있는지 확인하고 true를 반환하고 그렇지 않으면 false를 반환합니다.
크기 목록의 유효한 노드 수를 반환합니다.

목록 요소 액세스

함수 선언 인터페이스 설명
앞쪽 목록의 첫 번째 노드에 있는 값에 대한 참조를 반환합니다.
뒤쪽에 목록의 마지막 노드에 있는 값에 대한 참조를 반환합니다.

 목록 수정자

함수 선언 인터페이스 설명
push_front 목록의 첫 번째 요소 앞에 값이 val인 요소 삽입
pop_front 목록의 첫 번째 요소 삭제
푸시백 목록 끝에 값이 val인 요소 삽입
팝백 목록의 마지막 요소 삭제
끼워 넣다 목록 위치에 값이 val인 요소 삽입
삭제 목록 위치에서 요소 삭제
교환 두 목록의 요소 교환
분명한 목록에서 유효한 요소 지우기

목록의 반복자가 무효화됩니다.

 목록의 insert() 함수는 반복자 무효화가 없습니다. 이전에 벡터에 나타난 insert() 함수 반복자가 유효하지 않기 때문입니다. 벡터는 확장해야 하는 연속 공간이고 확장으로 인해 반복자가 실패 ; 그러나 목록에 데이터가 삽입될 때마다 새로운 공간을 만들어야 하며 목록의 기존 요소에는 영향을 미치지 않습니다.

그러나 erase() 함수와 같이 삭제된 함수의 경우 여전히 반복자 무효화를 저장하는 문제가 있습니다.

int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给
其赋值
l.erase(it);
++it;

위의 예와 같이 외부 반복자 무효화 문제로 자신이 가리키는 공간이 삭제되면 자신이 가리키는 공간도 해제되기 때문에 while문에서 오버로드된 연산자 함수 ++it는 다음을 찾을 수 없다. 위로.

개정;

while (it != l.end())
{
l.erase(it++); // it = l.erase(it);
}

 STL의 반복자 이해

 먼저 다음 세 함수의 서로 다른 반복자 유형을 살펴보겠습니다.

 

 위의 세 가지 반복자 유형이 있습니다.

  •  InputIterator: 단방향 반복자, ++ 연산만 사용할 수 있습니다.
  •  BidirectionalIterator: 양방향 반복기, ++ / -- 두 가지 작업을 사용할 수 있습니다.
  • RandomAccessIterator: 임의 반복자, ++ / -- / + / - 네 가지 작업을 사용할 수 있습니다.

 다른 컨테이너 유형에는 반복기 사용에 대한 요구 사항이 있습니다.

 예를 들어 단일 연결 목록은 단방향 반복자만 사용할 수 있고 양방향도 무작위도 사용할 수 없으므로 라이브러리의 양방향 및 임의 반복자로 구현된 함수의 경우 단일 연결 목록을 사용할 수 없습니다. 어느 하나.

하지만 이 3개의 이터레이터는 상위 호환이 가능합니다. 단방향, 양방향, 단방향의 경우 사용할 수 있습니다.

 목록의 모의 구현

 일반 프레임워크

#pragma once

namespace My_List
{
	template<class T>
	struct List_Node  // 结点指针结构体
	{
·············
	};

    template<class T>
	struct List_iterator // 非const 迭代器
	{
··········
    };

    template<class T>
	class List         // List 类
	{
············
        private:
		Node* _head;

	};
}

 노드 구조 정의 

 공식 List 소스 코드에서 List 컨테이너의 노드 정의는 동일한 네임스페이스 아래의 구조체에 정의되어 있는데 C++에서 구조체가 클래스로 업그레이드 되었기 때문에 생성자도 구조체에 정의할 수 있다.

따라서 노드에 숫자 필드와 포인터 필드가 있기 때문에 이 구조를 함수로 구현하여 노드를 구성하고 효과는 동일하지만 사용할 때 new를 사용하여 공간과 정의를 엽니다.

	template<class T>
	struct List_Node
	{
		List_Node<T>* _next;
		List_Node<T>* _prev;
		T _val;

		// List_Node 的构造函数
		List_Node(const T& val = T())
			:_next(nullptr),
			_prev(nullptr),
			_val(val)
		{}
	};

물론 숫자 필드의 재사용성을 위해 템플릿을 사용하여 숫자 필드의 유형을 템플릿화합니다.

 생성자와 소멸자

 매개변수가 없는 생성자

		List()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

List의 최하위 레이어는 헤드가 있는 원형 이중 연결 리스트이기 때문에 위와 같이 노드 없이 연결하기 위한 헤드 노드는 하나뿐입니다.

 오물 소각로

		~List()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

 clear() 함수는 여기에서 직접 재사용할 수 있습니다.

CRUD

 푸시백():

		void push_back(const T& x)
		{
			Node* tail = _head->_prev;
			Node* newNode = new Node(x);

			_head->_prev = newNode;
			tail->_next = newNode;

			newNode->_prev = tail;
			newNode->_next = _head;

            // 实现insert()函数之后
            // insert(end() , x);
		}

공간을 직접 열고 링크 관계를 수정합니다.

 삽입() 함수:

여기서 insert() 함수에 전달된 pos 포인터는 헤드 노드의 루프가 있는 연결 목록이고 헤드 노드 전후에서 삭제할 수 있기 때문에 유효성을 검사할 필요가 없습니다. 암호:

		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._Node;
			Node* prev = cur->_prev;
			Node* newNode = new Node(x);

			prev->_next = newNode;
			newNode->_next = cur:

			cur->_prev = newNode;
			newNode->_prev = prev;

			return newNode;
		}

요소가 pos 위치 이전에 삽입된 후 pos iterator가 뒤로 이동하기 때문에 이 또한 iterator 실패라고 생각하므로 외부 iterator가 무효화되지 않도록 새로 삽입된 요소의 위치를 ​​반환해야 합니다. 

지우기() 함수

 erase() 함수도 반복자 무효화 문제가 있으므로 새 반복자를 반환해야 합니다.

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* cur = pos._Node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;

			delete[] cur; // 这里会有 pos 迭代器失效的问题,所要要返回新的迭代器

			return next;
		}

 푸시 프론트():

 insert() 함수의 직접 재사용

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

 pop_back() 및 pop_front(): 

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

 클리어( )와 사이즈():

		size_t size()
		{
			return _size;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
			_size = 0;
		}

 할당 연산자 오버로딩 함수 및 swap() 함수

		void swap(List<T>& L)
		{
			std::swap(_head, L._head);
			std::swap(_head, L._size);
		}

		List<T>& operator(List<T> L)
		{
			swap(L);
			return *this;
		}

 위의 원칙은 다음 기사를 참조합니다. (1 메시지) C++-문자열 class_chihiro1122의 시뮬레이션 구현 블로그 - CSDN 블로그 의 대입 연산자 오버로드 함수 소개(비교 크기 제목 아래) .

사실 위에서 언급한 할당 오버로드 연산자 함수에서 템플릿 클래스의 타입 이름은 반드시 List<T>일 필요는 없으며 List<T>가 타입 이름이고 List가 클래스 이름이라는 것을 알고 있습니다. 템플릿 클래스의 경우 타입명은 List가 아닌 List<T>인데, 클래스 템플릿으로 작성하는 경우에는 클래스명이나 타입명을 기재할 수 있다 (다음 작성방법도 가능).

List& operator=(List L)

반복자(중요)

 비상수 반복자

 위에서 List iterator를 소개할 때 List 안의 iterator는 native pointer가 아니라 custom type이라 정의하기가 조금 어렵지만 이것의 장점은 a와 같다는 점이다. 일반 네이티브 포인터 이터레이터 직접 ++ 뒤로 이동, * 요소 액세스에 대한 역참조 등 사용자 정의 유형에 연산자 오버로드 함수가 있으므로 실현할 수 있습니다.

 사실 List의 반복자는 여전히 본질적으로 포인터이지만 포인터는 이제 데이터 필드뿐만 아니라 포인터 필드도 포함하는 노드 공간을 가리키므로 직접 역참조가 데이터 필드에 액세스할 수 없습니다. 이번에는 " * "(역참조) 연산자를 오버로드해야 하며 구현도 매우 간단합니다. 노드의 데이터 필드를 직접 반환하면 됩니다.

		T& operator* ()
		{
			return _Node->_val;
		}

 다음과 같이 반복자를 사용할 때 어떤 연산자를 사용할지 다시 생각해 봅시다.
 

	while (it != L.end())
	{
		cout << *it << " ";
		++it; // 因为只重载了 前置的++
	}
	cout << endl;

 위에서 사용된 작업을 오버로드해야 이 반복자를 정상적으로 사용할 수 있습니다.

		List_iterator<T>& operator++ ()
		{
			_Node = _Node->_next;
			return *this;
		}

		bool operator!= (const List_iterator<T>& L)
		{
			return _Node != L._Node;
		}

		bool operator== (const List_iterator<T>& L)
		{
			return _Node == L._Node;
		}

 마지막은 전체 반복자 구조의 구성입니다.위에서 언급한 바와 같이 C++는 구조를 클래스로 업그레이드하므로 생성자를 사용하여 반복자 개체를 구성할 수 있습니다.

우선, 이 반복자는 특정 노드에 대한 포인터인 멤버가 하나만 있으므로 이 구조의 생성자는 이 객체를 초기화하기만 하면 되고 구성할 때 이 노드의 값을 전달하기만 하면 포인터가 수행됩니다. :
 

		typedef List_Node<T> Node;
		Node* _Node;

		List_iterator(Node* node)
			:_Node(node)
		{}

 그런 다음 전체 non-const 반복자가 다음과 같이 구현됩니다.

	template<class T>
	struct List_iterator
	{
		typedef List_Node<T> Node;
		Node* _Node;

		List_iterator(Node* node)
			:_Node(node)
		{}

		T& operator* ()
		{
			return _Node->_val;
		}

		List_iterator<T>& operator++ ()
		{
			_Node = _Node->_next;
			return *this;
		}

		bool operator!= (const List_iterator<T>& L)
		{
			return _Node != L._Node;
		}

		bool operator== (const List_iterator<T>& L)
		{
			return _Node == L._Node;
		}
	};

 그런 다음 클래스에 begin() 및 end()의 두 인터페이스도 제공되어야 합니다. begin()은 헤드 노드 _head 중 마지막 노드를 가리키고 end는 _head를 가리킵니다.

		typedef List_iterator<T> iterator; // 一定要是公有的,不然不能访问
		iterator begin()
		{
			//return _head->_next; // 可以这样写,只有一个参数的构造函数发生 隐式类型的转换
		    // 上下两种都是一样的
			return iterator(_head->_next);
		}

		// 返回值应该是引用,要不然 != 函数会出错 传值返回返回的不是 _head 是 _head 的一个拷贝 
       // 临时对象具有常性  ······· 1
		iterator end()
		{
			return _head; // 同样发生隐式类型的转换
			// 上下两种都可以
			//return iterator(_head);
		}

 몇 가지 문제에 주의를 기울여야 합니다. 

  •  위 코드 주석에서 언급한 반환 값 유형은 참고 질문(1)이어야 하며 실제로는 이렇게 할 필요가 없습니다. 위의 begin() 및 end() 함수는 연산자!= 함수 및 생성자에서 사용됩니다. = 함수의 매개변수를 const 로 변경하기만 하면 위와 같이 변경됩니다.
  • My_List::List<int>::iterator it = L.begin(); 이것은 할당이 아니라 복사 구성입니다. L.begin()은 다른 개체에 대한 기존 개체 할당이므로 복사 생성자를 호출해야 하지만 iterator는 복사 구조를 구현하지 않습니다. 여기서 컴파일러에 의해 구현된 얕은 복사는 여기에서 문제가 되지 않습니다.
  • My_List::List<int>::iterator it = L.begin(); 여기에서 두 포인터는 모두 개체를 가리키고 있는데 컴파일러가 오류를 보고하지 않은 이유는 무엇입니까? 이는 반복자 클래스가 소멸자를 구현하지 않기 때문에 컴파일러는 기본 소멸자를 호출하여 반복자 포인터 공간을 해제하고 반복자가 가리키는 노드 공간은 해제할 반복자 클래스가 필요하지 않기 때문입니다. 수업의.

const 반복자

 여기에서 const 반복자는 const 개체를 대상으로 합니다. const 수정된 개체인 경우 일반 반복자가 사용되지 않습니다. non-const가 되어 권한이 증폭됩니다.

따라서 여전히 const 반복자를 별도로 구현해야 합니다.const 반복자의 기능은 operator* 함수에서 반환되는 것이 non-const 객체가 아니라 const 객체라는 점을 제외하면 일반 반복자와 유사합니다.

	template<class T>
	struct const_List_iterator
	{
		typedef List_Node<T> Node;
		Node* _Node;

		const_List_iterator(Node* node)
			:_Node(node)
		{}

		const T& operator* ()
		{
			return _Node->_val;
		}

		const_List_iterator<T>& operator++ ()
		{
			_Node = _Node->_next;
			return *this;
		}

		bool operator!= (const const_List_iterator<T>& L)
		{
			return _Node != L._Node;
		}

		bool operator== (const const_List_iterator<T>& L)
		{
			return _Node == L._Node;
		}
	};



		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}

이것은 const 반복자의 효과를 얻을 수 있지만 너무 중복되고 좋지 않습니다.

따라서 현재 우리는 아래와 같이 일반 반복자 클래스에 대한 템플릿인 여러 템플릿 매개 변수를 사용합니다.
 

	template<class T, class Ref>
	struct List_iterator
	{

······················

이 시점에서 클래스의 typedef 덤 드럼은 다음과 같이 작성됩니다.
 

		typedef List_iterator<T , T&> iterator; // 一定要是公有的,不然不能访问
		typedef List_iterator<T , const T&> const_iterator;

이와 같이 동일한 클래스에서 const 클래스와 non-const 클래스를 구분할 수 있으므로 opeartor* 함수의 수정은 다음과 같이 할 수 있습니다.

		Ref operator* ()
		{
			return _Node->_val;
		}

마찬가지로 클래스의 다른 위치를 수정해야 합니다. 전체 코드는 다음과 같습니다.

template<class T, class Ref>
	struct List_iterator
	{
		typedef List_Node<T> Node;
		typedef List_iterator<T,Ref> selt;
		Node* _Node;

		List_iterator(Node* node)
			:_Node(node)
		{}

		Ref operator* ()
		{
			return _Node->_val;
		}

		selt& operator++ ()
		{
			_Node = _Node->_next;
			return *this;
		}

		selt operator++ (int)
		{
			_Node = _Node->_next;
			return *this;
		}

		bool operator!= (const selt& L)
		{
			return _Node != L._Node;
		}

		bool operator== (const selt& L)
		{
			return _Node == L._Node;
		}
	};
	template<class T>
	class List
	{
		typedef List_Node<T> Node;

	public:
		typedef List_iterator<T , T&> iterator; // 一定要是公有的,不然不能访问
		typedef List_iterator<T , const T&> const_iterator;

·········································

이 경우 하나의 클래스가 작성되는 것 같지만 실제로는 두 개의 클래스가 작성되지만 코드의 크기가 절약되는 것이 템플릿의 장점입니다.

반복자에서 " -> " 연산자도 사용되므로 이 연산자도 오버로드해야 합니다.

		T* operator-> ()
		{
			return &_Node->_val;
		}

그런데 사용하다 보면 아래와 같은 장면이 조금 이상합니다.

struct A
	{
		A(int a1 = 0, int a2 = 0)
			:_a1(a1)
			, _a2(a2)
		{}

		int _a1;
		int _a2;
	};

	void test_list2()
	{
		list<A> lt;
		lt.push_back(A(1, 1));
		lt.push_back(A(2, 2));
		lt.push_back(A(3, 3));
		lt.push_back(A(4, 4));

		list<A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << " " << (*it)._a2 << endl;
			cout << it->_a1 << " " << it->_a2 << endl;

			++it;
		}
		cout << endl;
	}

 위의 cout 스트림에서 it 사용법은 실제로 다음과 같이 작성되어야 합니다.

it ->-> _a2

위는 일반적인 작성 방법이지만 operator->함수 사용시 it -> _a2로 그대로 사용한다.연산자 오버로딩은 가독성이 요구되기 때문에 컴파일러는 이 곳에서 ""를 생략하고 특수한 처리를 한다. -> ".

 위의 operator-> 함수가 const 반복자에서 구현된 경우 반환 값은 const T*여야 하므로 여기에서 사용할 반복자 클래스 템플릿의 매개 변수에 ptr을 추가합니다 .

최종 반복자에 대한 코드:

	template<class T, class Ref , class ptr>
	struct List_iterator
	{
		typedef List_Node<T> Node;
		typedef List_iterator<T,Ref, ptr> selt;
		Node* _Node;

		List_iterator(Node* node)
			:_Node(node)
		{}

		Ref operator* ()
		{
			return _Node->_val;
		}

		selt& operator++ ()
		{
			_Node = _Node->_next;
			return *this;
		}

		selt operator++ (int)
		{
			_Node = _Node->_next;
			return *this;
		}

		selt& operator-- ()
		{
			_Node = _Node->_prev;
			return *this;
		}

		selt operator-- (int)
		{
			_Node = _Node->_prev;
			return *this;
		}

		bool operator!= (const selt& L)
		{
			return _Node != L._Node;
		}

		bool operator== (const selt& L)
		{
			return _Node == L._Node;
		}

		ptr operator-> ()
		{
			return &_Node->_val;
		}
	};

template<class T>
	class List
	{
		typedef List_Node<T> Node;

	public:
		typedef List_iterator<T , T& , T*> iterator; // 一定要是公有的,不然不能访问
		typedef List_iterator<T , const T& , const T*> const_iterator;

·······················································

목록에 대한 역방향 반복자


이전 예제에서 우리는 역방향 반복자의 ++가 정방향 반복자의 --이고 역방향 반복자의 --가 정방향 반복자의 ++임을 알고 있으므로 역방향 반복자의 구현은 다음과 같이 할 수 있습니다. 순방향 반복자에 의해 실현됩니다. 즉, 역방향 반복자는 순방향 반복자를 포함할 수 있고 순방향 반복자의 인터페이스는 패키지화될 수 있습니다.
 

template<class Iterator>
class ReverseListIterator
{
	// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的类型,而不是静态成员变量
	// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
	// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
public:
	typedef typename Iterator::Ref Ref;
	typedef typename Iterator::Ptr Ptr;
	typedef ReverseListIterator<Iterator> Self;
public:
	//
	// 构造
	ReverseListIterator(Iterator it) : _it(it) {}
	//
	// 具有指针类似行为
	Ref operator*() {
		Iterator temp(_it);
		--temp;
		return *temp;
	}
	Ptr operator->() { return &(operator*()); }
	//
	// 迭代器支持移动
	Self& operator++() {
        --_it;
        return *this;
    }
    Self operator++(int) {
    	Self temp(*this);
    	--_it;
    	return temp;
    }
        Self& operator--() {
    	++_it;
    	return *this;
    }
    Self operator--(int)
    {
	    Self temp(*this);
	    ++_it;
	    return temp;
    }
//
// 迭代器支持比较
bool operator!=(const Self& l)const { return _it != l._it; }
bool operator==(const Self& l)const { return _it != l._it; }
Iterator _it;
};

리스트와 벡터의 비교

 목록은 연결 목록이고 벡터는 순차 목록입니다.이 둘의 구조가 다르기 때문에 사용 시나리오가 다릅니다.둘은 또한 연속 공간 저장 및 체인 공간 저장의 다른 특성을 나타내는 전형적인 표현입니다.다음 표는 a입니다. 두 비교의 간단한 요약:

벡터         목록
기본 구조 동적 시퀀스 테이블은 연속적인 공간입니다. 헤드 노드가 있는 이중 연결된 순환 목록
임의 접근 랜덤 액세스 지원, 요소 액세스 효율성은 O(1) Random 접근은 지원하지 않으며
요소 접근 효율은 O(N)
삽입 및 삭제 모든 위치에서 삽입 및 삭제는 비효율적이며 요소를 이동해야 함 시간 복잡도는
O(N) 삽입 시 용량을 늘려야 함 증가: 새로운 공간을 열고
요소를 복사하고 오래된 공간을 해제, 효율성 저하
임의의 위치에서 삽입 및 삭제가 매우 효율적이고 요소를 이동할 필요가 없으며
시간 복잡도는
O(1)
공간활용
최하층은 연속적인 공간으로 메모리 조각화, 높은 공간 활용률, 높은 캐시 활용률이 발생하기 쉽지 않습니다.
기본 노드는 동적으로 열리고 작은 노드는
메모리 조각화, 낮은 공간 사용률 및
낮은 캐시 사용률을 유발할 수 있습니다.
반복자 오리지널 에콜로틱 포인터 원래 생태 포인터(노드 포인터) 캡슐화
반복자 무효화
요소를 삽입할 때 요소를 삽입하면 다시 확장되어 원래 반복자가 무효화될 수 있으므로 모든 반복자를 재할당해야 하며 ,
삭제할 때는 현재 반복자를 재할당해야 하며 그렇지 않으면 무효가 됩니다.
요소를 삽입해도 이터레이터는 무효화되지 않으며
, 요소 삭제 시 현재
이터레이터만 무효화되고 다른 이터레이터는 영향을 받지 않습니다.
사용되는 장면 효율적인 저장이 필요하고 임의 액세스를 지원하며 삽입 및 삭제 효율성에 신경 쓰지 않습니다. 많은 삽입 및 삭제 작업, 임의
액세스 에 신경 쓰지 않음

추천

출처blog.csdn.net/chihiro1122/article/details/131899659