欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 『 C++入門到放棄 』 - vector 容器

『 C++入門到放棄 』 - vector 容器

2025/6/22 21:30:03 来源:https://blog.csdn.net/2503_90450246/article/details/148814040  浏览:    关键词:『 C++入門到放棄 』 - vector 容器

一、什麼是vector

  • vector是C++提供的一個容器(container),其底層邏輯類似於順序表

二、vector 接口

(1) 宣告 & 初始化

std::vector<int> v;              // 空 vector
std::vector<int> v(5);           // 初始化為 5 個 0(不給值默認為0)
std::vector<int> v(5, 10);       // 初始化為 5 個 10
std::vector<int> v = {1, 2, 3};  // 使用初始化列表

(2) 基本操作

v.push_back(4);     // 新增元素到尾端
v.pop_back();       // 移除尾端元素
v.size();           // 元素個數
v.empty();          // 是否為空
v.clear();          // 清空所有元素
v.resize(n) // 調整 vector 的「長度」為 n
// 若原本長度小於 n,會自動補上預設值(如 0)
// 若原本長度大於 n,多的元素會被移除

(3) 元素存取

// 使用索引
v[0] = 10;          // 不安全,沒範圍檢查
int x = v[1];
// 使用at()
v.at(1) = 20;       // 有範圍檢查(會拋出 exception)
// 首尾元素
v.front();          // 第一個元素
v.back();           // 最後一個元素

(4) 遍歷

// 1. for loop
for (int i = 0; i < v.size(); ++i)std::cout << v[i] << " ";
// 2. range-based for loop
for (int x : v)std::cout << x << " ";
// 3. Iterator
for (auto it = v.begin(); it != v.end(); ++it)std::cout << *it << " ";

(5) 插入刪除元素

// 1. 插入
v.insert(v.begin() + 2, 99);  // 在第 3 個位置插入 99
v.push_back(4) // 尾插 4// 2. 刪除
v.erase(v.begin() + 1);       // 移除第 2 個元素
v.pop_back() // 尾刪
v.clear() // 刪除所有元素

(6) 空間管理

// 預先配置空間
v.reserve(100);   // 提前分配空間(減少 realloc 次數)// 調整vector的size

三、vector模擬實現 (閹割版)

(1) vector 類的定義

template <class T> // 定義一個模板 => 提高代碼的泛用性
class vector{public:typedef T* iterator; // 自定義類型(為了更符合庫中的設計)typedef const T *const_iterator;private:iterator _start = nullptr; // 第一個元素的位置iterator _finish = nullptr; // 最後一個元素的位置iterator _end_of_storage = nullptr; // 容量
};

(2) vector 構造、析構、拷貝構造函數

std::vector<int> v;              // 空 vector
std::vector<int> v(5);           // 初始化為 5 個 0(不給值默認為0)
std::vector<int> v(5, 10);       // 初始化為 5 個 10// 1. 空 vector
vector(){}
// 2. 初始化為5個0 & 初始化為5個10
vector(size_t n, T& val = T()){resize(n,val);
}
// 3. 迭代器初始化 [first,last)
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);first++;}
}
// 析構
~vector()
{if (_start){delete[] _start;_start = nullptr;_finish = nullptr;_end_of_storage = nullptr;}
}
// 拷貝構造函數
// 深拷貝 => 默認為淺拷貝,對於自定義類型而言,若使用淺拷貝會發生問題
vector(const vector<T> &v)
{_start = new T[v.capacity()];// memcpy(_start, v._start, sizeof(T) * v.size()); // 所以不能使用memcpyfor (size_t i = 0; i < v.size(); ++i){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}

(3) 迭代器

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin() const
{return _start;
}
const_iterator end() const
{return _finish;
}

迭代器失效知識點:

vector erase和insert迭代器對象後,不能再訪問這個迭代器我們認為他失效,訪問結果是未定義

為什麼會有迭代器失效的問題?

insert後可能會擴容,而擴容後不一定是原地擴容,如果是異地擴容相當於當前的迭代器就不是指向新的空間,就會導致發生問題

erase 會讓 it 所指的那個位置從記憶體中移除,且後面元素整個搬移

造成:

  • it 所指的位置內容變動了
  • 甚至之後的 it + 1, it + 2 全部失效

解決方法:接回傳的 iterator

庫中對iterator回傳值的說明

An iterator pointing to the new location of the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

(4) 元素個數 & 空間大小

size_t size() const
{return _finish - _start; // 因爲_finish這個位置就是我們最後一個元素的位置 所以和第一個元素的位置相減就可以得到元素個數
}
size_t capacity() const
{return _end_of_storage - _start;
}

(4) 增刪街口

void push_back(const T &x)
{// if (_finish == _end_of_storage)// {//     // 擴容邏輯//     size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;//     reserve(new_capacity);// }// *_finish = x;// ++_finish;insert(end(), x);
}
void pop_back()
{erase(--end());
}
iterator insert(iterator pos, const T &x)
{assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start; // 保存pos的位置// 擴容邏輯size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;reserve(new_capacity);// 解決迭代器失效問題pos = _start + len;}iterator _end = _finish - 1;while (_end >= pos){*(_end + 1) = *_end;--_end;}*pos = x; // pos的類型是 T* 用解引用就可以直接改變pos指向的位置的值++_finish;return pos;
}
iterator erase(iterator pos)
{assert(pos >= _start && pos <= _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;++it;}--_finish;return pos;
}

(5) 空間配置

// 1. resize()
void resize(size_t n, T &val = T())
{if (n < size()){_finish = size() + 1;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}
}
// 2. reserve()
void reserve(size_t n)
{if (n > capacity()) // n 如果大於有效空間 就要擴容{size_t sz = size();T *tmp = new T[n];if (_start){// memcpy(tmp, _start, sizeof(T) * sz); // memcpy 自定義類型會有問題// 調用深拷貝for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz; // 不能直接調用size() 會崩潰_end_of_storage = _start + n;}
}

(6) 運算符重載

void swap(vector<T> &v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}
// 賦值
// v1 = v2
vector<T> &operator=(vector<T> v)
{swap(v); // 直接拷貝一個v2 然後在將 v1 的內容與 v2 相互對調即可 (因爲v2的拷貝構造出了此作用域後就會被銷毀)return *this;
}
T &operator[](size_t pos)
{assert(pos < size());return _start[pos];
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词