STL之Vector、Set、栈、队列

这篇博客介绍了C++ STL中的四个重要组件:vector、set、栈和队列。详细讲解了vector的简介、常用操作及算法,set的基本概念、优势和操作,以及栈和队列在数据结构中的应用。博客旨在帮助初学者理解STL的这些基本容器的使用和原理。

       互联网行业的小白,写博客的目的是为了记录自己的学习过程、对自己学习中所犯的错误做一个总结。由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!

1 STL之vector

1.1 vector简介

vector是C++提供的一个容器,它是一个能够存放任意类型的动态数组,可以随时增加和压缩数据。

使用vector时需要注意以下几点:

  • 如果要表示的向量长度较长(需要为向量内部保存很多数),容易导致内存泄漏,而且效率会很低;
  • vector作为函数的参数或者返回值时,需要注意它的写法` double Distance(vector&a, vector&b) 其中的“&”绝对不能少``

1.2 vector常用操作

1. 引入头文件

#include <vector>

2. 创建向量

vector<int> vec;

3. 向量尾部插入元素

vec.push_back(item);

4. 向量尾部弹出元素

vec.pop_back();

5. 访问向量元素

  • 下标访问
for(int i = 0; i < vec.size(); i++) {
    cout << vec[i] << endl;
}
  • 迭代器访问
vector<int>::iterator it;
for(it = vec.begin(); it != vec.end(); it++) {
    cout << *it << endl;
}

6. 插入元素

vec.insert(vec.begin() + i, item);  //在向量的第i+1的位置插入元素item

7. 删除元素

vec.erase(vec.begin() + i);  //删除向量的第i+1个元素

8. 向量的大小

vec.size();

9. 其他

vec.front();  //返回向量的第一个元素
vec.back();   //返回向量的最后一个元素
vec.empty();  //检测向量是否为空
vec.clear();  //清空向量

1.3 vector常用算法

以下算法使用时都需要包含头文件

#include <algorithm>

1. 翻转元素

//将向量中的元素翻转,即逆序排列
reverse(vec.begin(), vec.end());        

2. 排序

//将元素以升序排列(由小到大)
sort(vec.begin(), vec.end());        
//定义排序比较函数
bool compare(const int &a, const int &b) {
    return a > b;
}
//将元素以降序排列(由大到小)
sort(vec.begin(), vec.end(), compare);        

3. 查找

//查找向量中的值为10的元素
find(vec.begin(), vec.end(), 10);        

4. 复制

//把vec向量中所有元素全部复制到vec_1向量中,从vec_1.begin() + 1 的位置开始复制,覆盖掉原有的元素
copy(vec.begin(), vec.end(), vec_1.begin() + 1);        

2 STL之set

2.1 Set简介

Set是STL中的一个容器,特点是其中包含的元素值是唯一的,set根据其底层实现机制分为hash存储和红黑树存储两种方式,这两种结构最本质的区别就是有序和无序,红黑树的存储是有序的而hash表是无序存储,但它并不影响set的最主要的用法就是查找,而从查找角度来说hash表是更优于红黑树,从时间复杂度进行分析,红黑树的时间复杂度为O(logN),而hash表的时间复杂度为O(1)。所以说hash表构建的set更高效。所以在对时间要求比较严格的情况下,可以优先采用hash表构建的set,即unordered_set。

平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。

使用Set的主要目的是为了快速检索,特点是相同的值不存,存入的值按照顺序排列好。

当集合中的元素增加时,搜索集合速度的变化趋势如下

在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。明白这个道理后,就可以安心往里面放入元素了。

2.2 set的常用操作

1. 引入头文件

#include <set>

2. 创建集合

set<int> s;

3. 插入元素

s.insert(item);

4. 正向访问元素

  • 使用迭代器iterator
set<int>::iterator it;

for (it = s.begin(); it != s.end(); it++) {
    cout << *it << endl;  
}

5. 逆向访问元素

  • 使用逆向迭代器reverse_iterator
set<int>::reverse_iterator rit;

for (rit = rbegin(); rit != rend(); rit++){
    cout << *rit << endl;
}

6. 删除元素

s.erase(item);
s.erase(it);        //it是指向集合中某元素的一迭代器

7. 检索元素

set<int>::iterator it;
it = s.find(item);        //查找集合中值为item的元素并把地址返回给迭代器it

8. 检索某一元素是否存在于集合中
count方法本身时检测集合中某一元素的出现次数,但在集合中不存在重复元素,因此count就变为检测元素是否存在的方法

s.count(item);

9. 集合中的元素数

s.size();

10. 检测集合是否为空

s.empty();

11. 清除集合中的所有元素

s.clear();

12. Set常用函数:

begin()--返回指向第一个元素的迭代器

end()--返回指向最后一个元素的迭代器

equal_range()--返回集合中与给定值相等的上下限的两个迭代器

get_allocator()--返回集合的分配器

lower_bound()--返回指向大于(或等于)某值的第一个元素的迭代器

key_comp()--返回一个用于元素间值比较的函数

max_size()--返回集合能容纳的元素的最大限值

rbegin()--返回指向集合中最后一个元素的反向迭代器

rend()--返回指向集合中第一个元素的反向迭代器

swap()--交换两个集合变量

upper_bound()--返回大于某个值元素的迭代器

value_comp()--返回一个用于比较元素间的值的函数

3 STL之栈的应用

Stack容器:

1)容器适配器,遵循先进后出(FILO)数据结构。

2)头文件:#include <stack>

3)常用函数:
stack<int>s;

s.empty()//如果栈为空返回true,否则返回false  
s.size()//返回栈中元素的个数  
s.pop()//删除栈顶元素但不返回其值  
s.top()//返回栈顶的元素,但不删除该元素  
s.push(X)//在栈顶压入新元素 ,参数X为要压入的元素

例子:

#include<stack>
#include<iostream>
using namespace std;

int main() {
    stack<int>s;
    int a[8] = { 3,5,17,9,30,15,2,4 };

    for (int i = 0; i < 8; i++) {
        s.push(a[i]);//入栈
    }

    cout << s.size() << endl;//栈中所有元素个数

    cout << s.top() << endl;//栈顶元素

    //依次输出栈中所有元素
    while (!s.empty()) {
        cout << s.top() << " ";
        s.pop();
    }
    cout << endl;

    //没有自动清空的栈的函数,应这样实现
    while (!s.empty()) {
        s.pop();
    }
    return 0;
}

数据结构实现:

#include<iostream>
using namespace std;

const int MAXN = 100;//栈的最大长度

//定义栈
struct Stack {
    int *stack;
    int top;
};

//初始化栈
void InitStack(Stack& s) {
    s.stack = new int[MAXN];
    s.top = -1;
}

//入栈
void Push(Stack &s, int item) {
    s.top++;
    s.stack[s.top] = item;
}

//出栈
int Pop(Stack& s) {
    s.top--;
    return s.stack[s.top + 1];
}

//读取栈定元素
int Peek(Stack s) {
    return s.stack[s.top];
}

//清空栈
void ClearStack(Stack& s) {
    if (s.stack) {
        delete[]s.stack;
        s.stack = 0;
    }
    s.top = -1;
}

//判断栈是否为空
bool EmptyStack(Stack s) {
    return s.top == -1;
}

int main() {
    Stack s;
    InitStack(s);
    int a[8] = { 3,5,17,9,30,15,2,4 };
    for (int i = 0; i < 8; i++) {
        Push(s, a[i]);
    }
    cout << Peek(s) << endl;
    //注意输出采用如下方式
    while (!EmptyStack(s)) {
        cout << Pop(s) << " ";
    }
    ClearStack(s);
    return 0;
}

4 STL之队列的应用

Queue队列容器:

1)容器适配器,遵循先进先出(FIFO)数据结构。

2)头文件:#include <queue>

3)常用函数:
queue<int>q;

q.empty()// 如果队列为空返回true,否则返回false  
q.size() // 返回队列中元素的个数  
q.pop()  //删除队列首元素但不返回其值  
q.front()  // 返回队首元素的值,但不删除该元素  
q.push(X) //在队尾压入新元素 ,X为要压入的元素
q.back() //返回队列尾元素的值,但不删除该元素

例子:

#include<queue>
#include<iostream>
using namespace std;

int main() {
    queue<int>Q;
    int a[] = { 3,5,17,9,30,15,2,4 };
    int l = sizeof(a) / sizeof(int);

    for (int i = 0; i < l; i++) {
        Q.push(a[i]);//入队
    }

    cout << Q.back() << endl;//输出队尾元素

    cout << Q.front() << endl;//输出队首元素

    cout << Q.size() << endl;//输出队列的长度

    Q.pop();//出队,注意此函数并不返回任何值

    //输出队列中的所有元素
    while (!Q.empty) {
        cout << Q.front() << " ";
        Q.pop();
    }

    //清空队列
    while (!Q.empty) {
        Q.pop();
    }
    return 0;
}

数据结构实现:

//队列:队首出,队尾进(先进先出表)
#include<iostream>
using namespace std;

const int MAXN = 1000 + 5;

struct Queue {
    int *queue;
    int front;
    int rear;
    int len;
};

//初始化队列
void InitQueue(Queue& Q) {
    Q.queue = new int[MAXN];
    Q.front = Q.rear = 0;
    Q.len = 0;
}

//入队
void InsertQueue(Queue& Q, int item) {
    Q.rear = (Q.rear + 1) % MAXN;
    Q.queue[Q.rear] = item;
    Q.len++;
}

//清空队列
void ClearQueue(Queue& Q) {
    if (Q.queue != NULL) delete[] Q.queue;
    Q.front = Q.rear = 0;
    Q.queue = NULL;
    Q.len = 0;
}

//出队
void PopQueue(Queue& Q) {
    Q.front = (Q.front + 1) % MAXN;
    Q.len--;
}

//求队首元素
int PeekQueue(Queue Q) {
    return Q.queue[(Q.front + 1) % MAXN];
}

//判断队列是否为空
bool EmptyQueue(Queue Q) {
    return Q.front == Q.rear;
}

int main() {
    Queue Q;
    InitQueue(Q);

    int a[] = { 2,4,5,6,7,9,10,3 };
    int l = sizeof(a) / sizeof(int);
    for (int i = 0; i < l; i++) {
        InsertQueue(Q, a[i]);
    }

    cout << Q.len << endl;//输出队列的长度

    cout << PeekQueue(Q) << endl;//查看队首元素

    PopQueue(Q);//删除队首元素
    PopQueue(Q);//删除队首元素

    //依次输出队列的元素
    while (!EmptyQueue(Q)) {
        cout << PeekQueue(Q) << " ";
        PopQueue(Q);
    }

    ClearQueue(Q);//清空队列
    return 0;
}

hhh

码字不易,您的支持就是我坚持下去的动力,一起加油哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值