C通用算法——全局算法

全局算法

全局算法通常指的是不依赖于特定数据结构或对象,而是可以在各种数据集合上使用的通用算法。这些算法通常定义在标准模板库(STL)中,因此可以在整个程序中重复使用,适用于多种数据 类型。

头文件

<algorithm>

1 遍历算法

  • std::for_each

std::for_each算法用于对容器中的每个元素执行指定的函数或操作。它接受一个迭代器范围(开始和 结束迭代器)和一个函数对象(可以是函数指针、lambda表达式或函数对象类实例

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void Double(int &n)
{
    n *= 2;
}
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5};
    // 函数名用作参数时,实际上传递的是函数的指针
    std::for_each(v.begin(), v.end(), Double);
    std::for_each(v.begin(), v.end(),[] (int n)
    {
        cout << n << " ";
       
    });
    cout << endl;

    return 0;
}
  • std::copy

    std::copy算法用于将一个容器中的元素复制到另一个容器中。它同样接受一个迭代器范围和一个输出 迭代器,用于指定复制的目标位置

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    void Double(int &n)
    {
        n *= 2;
    }
    int main()
    {
        std::vector<int> v{1, 2, 3, 4, 5};
        // 函数名用作参数时,实际上传递的是函数的指针
        std::for_each(v.begin(), v.end(), Double);
        std::for_each(v.begin(), v.end(),[] (int n)
                {
                 cout << n << " ";});
        cout << endl;
        // 复制
        std::vector<int> l;
        std::copy(v.begin(), v.end(),l.begin() );
        std::for_each(l.begin(), l.end(),[] (int n)
        {
         cout << n << " ";});
         cout << endl;
        return 0;
    }
    
  • std::transform

    std::transform算法用于对容器中的每个元素应用一个函数或操作,并将结果存储在另一个容器中。 只能操作不能输出。

  • std::replace 和 std::replace_if

std::replace算法用于将容器中所有等于给定值的元素替换为另一个值。

   std::vector<int> v{1, 2, 3, 4, 5};
   std::replace(v.begin(), v.end(), 2, 100);
     std::for_each(v.begin(), v.end(),[] (int n)
                    { cout << n << " ";});

而std::replace_if则根据指定的条件来替换元素。

     std::vector<int> v{1, 2, 3, 4, 5};
    std::replace_if(v.begin(), v.end(),[](int n)
                    {return n < 10;} , 1); 
    std::for_each(v.begin(), v.end(),[] (int n)
                     {cout << n << " ";});

2 查找算法

查找算法是在整个数据集中搜索特定元素或满足特定条件的元素的算法。C++标准库提供了一些用于查 找的算法,这些算法可以在各种容器(如向量、列表、集合等)中使用。

  • std::find
  • std::find算法用于在给定范围内查找指定元素。它接受两个迭代器(表示范围的开始和结束)和一个 要查找的值作为参数,并返回一个指向找到的元素的迭代器,如果未找到则返回结束迭代器(end())
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 3, 6};
    std::vector<int>::iterator it = std::find(v.begin(), v.end(), 3);
    if(it == v.end())
    {
        cout << "没找到" << endl;
    }
    else
    {
        cout << *(it +1) << endl;
    }
    

std::find_if

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool isEven(int n)
{
        return  n % 2 == 0;
        // return n > 3;
}
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 3, 6};
    std::vector<int>::iterator it = std::find(v.begin(), v.end(), 3);
    if(it == v.end())
    {
        cout << "没找到" << endl;
    }
    else
    {
        cout << *(it +1) << endl;
    }
    it = std::find_if(v.begin(), v.end(), isEven);
    if( it ==v.end())
    {
        cout << "没找到" <<endl;

    }
    else
    {
        cout << *it << endl;
    }
    return 0;
}
  • std::find_first_of

std::find_first_of算法用于在第一个范围内查找与第二个范围中任何元素匹配的第一个元素

	#include <iostream>  
	#include <vector>  
	#include <algorithm>
	int main()
	{
		std::vector<int> v{1, 2, 3, 4, 5, 3, 6};
 		std::vector<int> v1{5, 4, 6, 5};
    	it = std::find_first_of(v.begin(), v.end(), v1.begin(), v1.end());
    	if( it ==v.end())
    	{
        	cout << "没找到" <<endl;

   	 	}
    	else
    	{
        	cout << *it << endl;
   		 }
	}
	
  • std::search

    std::search算法用于在给定范围内查找与另一个范围**完全匹配(包含顺序)**的子序列。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 3, 6};
    // std::search算法用于在给定范围内查找与另一个范围完全匹配的子序列。
    std::vector<int> v2{4, 5};
    it = std::search(v.begin(), v.end(), v2.begin(), v2.end());
    if( it ==v.end())
    {
        cout << "没找到" <<endl;

    }
    else
    {
        cout << *it << endl;
    }
    // 
    return 0;
}

3 排序算法

  • std::sort

是最常用的排序函数之一,它对一个给定范围内的元素进行排序。这个函数使用快速排序、 归并排序或堆排序等算法,具体实现取决于标准库的实现和编译器的优化。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    std::vector<int> v{1, 3, 5, 2, 4};
    std::sort(v.begin(), v.end());
            for_each(v.begin(), v.end(), [](int n)
            {cout << n <<" "; });
    return 0;
}

4 划分算法

std::partition

std::partition 是 C++ 标准库中的一个算法,它用于对容器(或序列)中的元素进行分区。该算法重 新排列元素,使得所有满足某个谓词的元素都出现在不满足该谓词的元素之前。

#include <vector>  
#include <algorithm>  
#include <iostream>  
bool isEven(int n) 
{
    return n % 2 == 0;
 }
 int main() 
{
    std::vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    // 使用 std::partition 将偶数放在前面,奇数放在后面  
    std::partition(numbers.begin(), numbers.end(), isEven);
    // 输出分区后的元素  
    for (int num : numbers) 
    {
        std::cout << num << ' ';
    }
    std::cout << std::endl;
    return 0;
 }

5 迭代器算法

std::distance(InputIterator first, InputIterator last)

std::distance 是 C++ 标准库中的一个函数,定义在 头文件中。它用于计算两个迭代器 之间的距离,即它们之间元素的数量。这个函数特别有用,因为它可以适用于各种类型的迭代器。

++it it++ 所有容器都支持

–it it-- 单向容器(比如list):除单向链表外都支持

it+/- it[n] 在内存空间连续才支持

#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

int main()
{
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::vector<int>::iterator first = vec.begin();
    std::vector<int>::iterator second = first + 2;
    std:size_t distance = std::distance(first, second);
    cout << distance << endl;

    return 0;
}
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

int main()
{
      // 正数前进 附属后退 next
     std::list<int> l ={1, 2, 3, 4, 5};
     //  std::list<int>::iterator l_first(l.begin());
     std::list<int>::iterator l_first(l.end());
     std::advance (l_first, -3);
     cout << *l_first << endl;

}

  • std::next

std::next 是 C++ 标准库中的一个函数,它定义在 头文件中。 std::next 用于返回指 向给定迭代器之后某个位置的迭代器。这个函数在需要获取迭代器之后某个元素的位置时非常有用。

template<class InputIt>
InputIt next(InputIt it, typename iterator_traits<InputIt>::difference_type n =
1);
//InputIt 是输入迭代器的类型。
//it 是当前的迭代器。
//n 是你想要前进的步数,默认值为1

在这个例子中, std::next 返回了一个新的迭代器 next_it ,它指向 vec 中的第四个元素(值 为4)。同时,原始的迭代器 it 仍然指向第一个元素。

#include <iostream>
#include <vector>
#include <iterator>
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5 };
// 获取指向第一个元素的迭代器
std::vector<int>::iterator it = vec.begin();
// 获取指向第二个元素的迭代器
std::vector<int>::iterator next_it = std::next(it, 3);
// 输出第四个元素的值
std::cout << "The value at the iterator is: " << *next_it << std::endl;
// 输出原始迭代器的值,它仍然指向第一个元素
std::cout << "The value at the original iterator is: " << *it << std::endl;
return 0;
}

6 内存管理

<memory>是 C++ 标准库中的一个头文件,它提供了与内存管理相关的各种算法。这些算法和容器适配 器有助于动态管理内存,包括动态分配和释放内存,以及使用智能指针来自动管理内存的生命周期

  • std::shared_ptr

    • std::shared_ptr 是 C++ 标准库 头文件中定义的一个模板类,它实现了一个共享所有权的 智能指针,。 std::shared_ptr 允许多个智能指针实例共享同一个对象的所有权。用于复制

    • std::shared_ptr 通过引用计数来管理对象的生命周期。每个 std::shared_ptr 实例内部持有一个 指向控制块的指针,这个控制块包含了所指向对象的指针以及一个引用计数。每次复制 std::shared_ptr时,引用计数就会增加;每次销毁或重置 std::shared_ptr 时,引用计数就会减 少。当引用计数减少到 0 时, std::shared_ptr 就会自动删除它所指向的对象。

    • 使用 std::shared_ptr 可以避免手动管理内存时可能出现的许多问题,如内存泄漏和野指针

    • 头文件

    #include <memory>
    
    • 定义std::shared_ptr对象
    std::shared_ptr<类型名称> ptr1;
    
    • 初始化std::shared_ptr对象
    std::shared_ptr<类型名称> ptr1 = std::make_shared<类型名称>();
    
    

    示例:

    #include <iostream>
    #include <memory>
    using namespace std;
    // 类
    struct MyStruct
    {
    public:
        MyStruct(int value = 0): m_value(value){};
        ~MyStruct()
        {
            cout << "析构函数: "  << m_value << endl;
        }
    private:
        int m_value;
    };
    
    int main()
    {
        // 定义智能指针
        std::shared_ptr <MyStruct> ptr1 = std::make_shared<MyStruct>(10);
        // 复制ptr,增加计算
        std::shared_ptr <MyStruct> ptr2 = ptr1;
        cout << "count = " << ptr1.use_count() << endl;
        // 输出当前引用计数
        {
            std::shared_ptr <MyStruct> ptr3 = ptr1;
            cout << "count = " << ptr1.use_count() << endl;
        }
        cout << "count = " << ptr1.use_count() << endl;
        return 0;
    }
    
  • std::unique_ptr

  • std::unique_ptr 是一种独占所有权的智能指针。它不允许复制,但允许移动。用于移动语义,这意味着在任何时候, 都只有一个 unique_ptr 可以拥有对象的所有权。当 unique_ptr 离开其作用域或被销毁时,它所指向 的对象也会被自动删除。

    • 定义std::unique_ptr对象
    std::unique_ptr<类型名称> ptr1;
    
    • 初始化std::unique_ptr对象
std::unique_ptr<类型名称> ptr1;

示例

#include <iostream>
#include <memory>
using namespace std;
// 类
struct MyStruct
{
public:
    MyStruct(int value = 0): m_value(value){};
    ~MyStruct()
    {
        cout << "析构函数: "  << m_value << endl;
    }

    int m_value;
};

int main()
{
    

    //使用  std::unique创建std::unique ptr3
    std::unique_ptr<MyStruct> ptr_unique = std::make_unique<MyStruct>(42);
    // 输出 ptr 指向的对象的值
    cout << "value = " << ptr_unique->m_value << endl;
    // std::unique_ptr<MyStruct> ptr2 = ptr_unique ; // error:不能拷贝复制 
    //std::unique_ptr<int> ptr3(ptr_unique); // error:不能拷贝构造 底层都删掉了
    std::unique_ptr<MyStruct> ptr_unique2 = std::move(ptr_unique);//可以移动构造
    ptr_unique = nullptr;
    cout << "value = " << ptr_unique2 ->m_value << endl;

    return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

  • std::weak_ptr

std::weak_ptr 是一种不控制对象生命周期的智能指针,它指向一个由 shared_ptr 管理的对象。 weak_ptr 的主要目的是为了解决 shared_ptr 之间的循环引用问题。它不会增加引用计数,因此不会 导致对象被错误地保持活动状态。这在你需要访问一个对象,但又不想拥有它的所有权时非常有用,比 如你想在对象的生命周期内保持对它的引用,但又不想阻止对象被删除。

#include <iostream>
#include <memory>
using namespace std;
// 类
class CB;
class CA
{
public:
    CA()
    {
        std::cout << "CA()" << std::endl;
    }
    ~CA()
    {
        std::cout << "~CA()" << std::endl;
    }
    void set_ptr(std::shared_ptr<CB>& ptr)//引用传递 避免拷贝,提高效率
    //std::shared_ptr<CA>& ptr error      CA 的定义依赖于自身的完整定义,而 std::shared_ptr<CA> 也需要知道 CA 的完整定义来正确管理内存。
// 因此,std::shared_ptr<CA> 在类定义内部是不合法的,因为它会导致循环依赖
    {
        m_ptr_b = ptr;
    }   
     
private:
    std::shared_ptr<CB> m_ptr_b;
};
class CB
{
    public:
    CB()
    {
    std::cout << "CB()" << std::endl;
    }
    ~CB()
    {
    std::cout << "~CB()" << std::endl;
    }
    void set_ptr(std::shared_ptr<CA>& ptr)
    {
    m_ptr_a = ptr;
    }
    private:
        // std::shared_ptr<CA> m_ptr_a;
        std::weak_ptr<CA> m_ptr_a;
};
int main()
{
    std::shared_ptr<CA>/*CA类的 */ ptr_A(new CA()/*CA类的 */);
    std::shared_ptr<CB> ptr_B(new CB());
    ptr_A ->set_ptr(ptr_B);
    ptr_B ->set_ptr(ptr_A);
    cout << ptr_A.use_count() << " " << ptr_B.use_count() << endl;
    std::shared_ptr<CB> m_ptr_b;
    // 为什么没有调用析构函数,因为shared_ptr循环引用了,你中有我,我中有你,ptr_A和ptr_B断开,但是m_ptr_a和
    // m_ptr_b指向的对象没有断开,引进计数每个还是一个
    return 0;
}

在这里插入图片描述

由图示这个std::weak_ptr m_ptr_a没有引用计数,释放时候CB的引用计数变成0,可以调到析构,释放所占内存,成员变量也释放了,3也就消失了,于是CA的引用计数也变成0,于是调用析构函数释放内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值