C++學習14-容器的不同數據結構簡介

容器分爲順序/關聯/…

C++ STL 組件之一: 容器
順序容器

  • vector 一維數組 push_back / pop_back
  • deque 雙端隊列 push_back/pop_back push_front/pop_front
  • list 雙向循環鏈表容器 push_back/pop_back push_front/pop_front

容器適配器: 沒有迭代器 沒有自己的數據結構
自己啥方法也沒 都調的別人的方法 沒有自己的數據結構 是把別人的封裝了一下 就是工具類

  • stack 棧 push pop top size empty
  • queue 隊列 push pop front back size empty
  • priority_queue 大根堆/小根堆 push pop top size empty

關聯容器
set集合(key) map映射表(key-value)
無序的關聯容器(哈希表 增刪查時間複雜度O(1))
無序關聯容器 =》 鏈式哈希表
unordered_set
unordered_map

有序的關聯容器(紅黑樹 增刪查時間複雜度O(logn))
有序關聯容器 =》 紅黑樹
set
map

近容器
char array[100]; char *p
string str;
bitset 位容器
(數組也叫容器 string也叫容器 近容器)
bitset 位容器(佔大小不是0就是1)

順序容器:

容器交換函數  swap 效率怎麼樣?
直接對指針進行交換(地址的交換) 效率高  沒有對內存的開闢構造釋放
PS:array是內存不變數據變

1.vector: 向量容器

2倍擴容的一維數組
push_back O(1) insert(it, val) O(n)
pop_back O(1) erase(it) O(n)
尾刪 o(1) 頭刪O(n)
迭代器遍歷 O(n)
operator[] 隨機訪問 O(1)

效率相關的方法
reserve(10) resize(10)—兩個都會開闢空間 但是reserve只開闢不放內存
empty size front back…

vector<int> vec;
vector<vector<int>> vec;  二維數組數據結構的容器開闢
vector<list<int>> vec;
list<vector<int>> vec;

2.deque : 雙端隊列容器

deque容器爲一個給定類型的元素進行線性處理,像向量一樣,
它能夠快速地隨機訪問任一個元素,並且能夠高效地插入和刪
除容器的尾部元素。但它又與vector不同,deque支持高效插入
和刪除容器的頭部元素,因此也叫做雙端隊列。

動態開闢的二維數組
push_back O(1) push_front O(1) insert(it, val) O(n)
pop_back O(1) pop_front O(1) erase(it) O(n)
迭代器遍歷 O(n)

擴容的時候默認擴容第一維 二倍擴容 把第二維的放在第一維擴容的
在這裏插入圖片描述
內存不連續 所以deque的使用效率比vector高一些 頭插尾插兩個一樣快 但是從中間插入的時候vector更快
empty size front back…

3.list : 鏈表容器

帶頭節點的雙向鏈表結構
push_back O(1) push_front O(1) insert(it, val) O(1)
pop_back O(1) pop_front O(1) erase(it) O(1)
迭代器遍歷 O(n)

增加刪除用list 隨機訪問用vector

效率相關的方法 splice函數

list::splice實現list拼接的功能。
將源list的內容部分或全部元素刪除(直接拿來 然後直接指針指向)
拼插入到目的list。
函數有以下三種聲明:
void splice ( iterator position, list<T,Allocator>& x );  //
void splice ( iterator position, list<T,Allocator>& x, iterator i );
void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last );
函數說明:在list間移動元素

將x的元素移動到目的list的指定位置,高效的將他們插入到目的list並從x中刪除。
目的list的大小會增加,增加的大小爲插入元素的大小。x的大小相應的會減少同樣的大小。
前兩個函數不會涉及到元素的創建或銷燬。第三個函數會。
指向被刪除元素的迭代器會失效。

empty size front back…

失效問題:
當對容器進行增加或者刪除操作時 要進行刷新

// 迭代器的失效問題
    for (auto it = vec.begin();
        it != vec.end();
        ++it)
    {
        if (*it > 20)
        {
            it = vec.insert(it, 100);  
//不能只寫成vec.insert(it, 100)
            ++it;
        }
    }

容器適配器

1.stack : 棧

底層用deque存儲的元素,調的是deque的方法
stack s1;
stack<int, vector> s2;//自己指定了用vector做容器container
s1.push(10); s1.pop(); s1.top(); s1.empty(); s1.size()

爲什麼默認用deque不用vector?

1.初始的時候deque的二維已經有一段空間,而vector
默認沒空間.所以初始內存利用率不高 用deque
2.deue的空間不連續,所以插入刪除的效率高

2.queue : 隊列

底層用deque存儲的元素,調的是deque的方法
queue q1;
queue<int, vector> q1;
q1.push(10); q1.pop(); q1.front(); q1.back(); empty size

爲什麼默認用deque不用vector?
1.頭尾操作方便

3.priority_queue :優先級隊列

vector 優先級隊列 默認實現是一個大跟堆
有優先級 不是每次出都是從頭出 用堆實現(把優先級最高的放堆頂) 因爲大跟堆,所以出隊時出的是元素中最大的

priority_queue<int> pq;
priority_queue<int, deque<int>> pq;
pq.push(10);
pq.push(45);
pq.push(31);
pq.push(21);
pq.push(89);
while(!pq.empty())
{
    int top = pq.top();..用top返回
    cout<<top<<endl;   // 89 45 31 21 10
    pq.pop();//只出不返回
}

爲什麼默認用vector不用deque?
1.要建一個堆,堆節點查找要用數組下標來找,所以要在連續內存上才能計算下表.
優先級隊列 求解大數據的top k問題

優先級隊列的底層默認參數:

class _Ty,//數據
class _Container = vector<_Ty>,//容器類型
class _Pr = less<typename _Container::value_type> >//函數類型
int main()
{
vector<int> vec;
for (int i = 0; i < 100000; ++i)
{
vec.push_back(rand() % 10000);
}


unordered_map<int, int> map;
for (int val : vec)
{
map[val]++;
}


// function 函數對象類型
// 小堆結構 priority_queue<pair<int, int>, vector<pair<int, int>>, greater>
using P = pair<int, int>;
using FUNC = function<bool (P&,P&)>;
using MinHeap = priority_queue<P, vector<P>, FUNC>;
MinHeap minHeap([](auto &a, auto &b)->bool
{
return a.second > b.second;
});


for_each(map.begin(),
map.end(),
[&minHeap](auto &pair)->void
{
if (minHeap.size() < 5)
{
minHeap.push(pair);
}
else
{
if (pair.second > minHeap.top().second)
{
minHeap.pop();
minHeap.push(pair);
}
}
});


while (!minHeap.empty())
{
cout << "數字:" << minHeap.top().first << " 重複次數:"
<< minHeap.top().second << endl;
minHeap.pop();
}
cout << endl;


return 0;
}

關聯容器

集合key 映射表 [key,value] id -> Student

1.有序容器
紅黑樹

紅黑樹  insert/erase/query:O(log2n)  O(1) > O(log2n) > O(n) > O(n^2)
       有序的
8  12   23   35   47   59   62   69  78  89   95
                       59
            23                      78
     8            35           62           89
        12           47          69             95

2.無序容器
鏈式哈希表 O(1)

普通的哈希表是key的值和value的值一模一樣,即以數據值的本身作爲數組的下標,這是直接映射,比如array[2],array[20],array[35] 就要開36個空間,用key直接訪問,所以增刪查改都是O(1),但空間的佔用太多了.
在這裏插入圖片描述
散列哈希表:
**散列技術是在記錄的存儲位置和他的關鍵字之間建立一個確定的對應關係f,**是的每個關鍵字key對應一個存儲位置f(key)。查找時,根據這個對應的關係找到給定值key的映射f(key),若查找集合中存在這個記錄,則必定在f(key)的位置上。我們把這種對應關係f稱爲散列函數,又稱爲哈希(Hash)函數。

映射函數叫做散列函數,存放記錄的數組叫做散列表。
散列函數的定義:

關鍵字key對應一個存儲位置f(key)。查找時,
根據這個對應的關係找到給定值key的映射f(key),
若查找集合中存在這個記錄,則必定在f(key)的位置上。
我們把這種對應關係f成爲散列函數

哈希表的定義下一節再詳細說明

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章