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成为散列函数

哈希表的定义下一节再详细说明

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