前 3 篇先后介绍了 链表、数组、map集合,它们都是用来存储数据的,stl 和 util 还提供了很多基于这些集合类的算法:
一 copy
首先介绍的这个算法好像根本就称不上是算法,不过它确实挺有用的:
假如我们有一组数据要存到一个集合类中,并假设这组数据在编码过程中经常需要改动,所以我们尽量要做到数据变动的时候不需要改动其他代码。我们可以先临时定义一个数组,列出这些数据,然后用一个 for 循环一个一个地把它们添加进去。但是 stl 告诉我们可以不用循环:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
// 打印 begin 到 end 之间的所有数据
// InIt 是输入迭代器,可视为指针
template<class InIt>
void displayAll(InIt begin, InIt end)
{
if(begin != end)
{
--end;
for(; begin!=end; ++begin)
cout<<*begin<<",";
cout<<*end;
}
cout<<endl;
}
// 求数组A的长度
#define LENGTH(A) (sizeof(A)/sizeof(A[0]))
int main()
{
int A[] = {5,3,1,13,8,1,2};
vector<int> C;
// 将 A 到 A + LENGTH(A) 之间的数据拷贝到 C 中
// inserter 模版函数返回一个插入迭代器,iterator 头文件友情提供
copy(A, A + LENGTH(A), inserter(C, C.end()));
displayAll(C.begin(), C.end());
return 0;
}
java 中也有类似的功能,但是介绍它之前请允许我先总体地介绍一下算法在 stl 和 util 中的位置:
从上例中也可以看出 stl 中的算法在头文件 algorithm 中;而 util 中的算法则在 util 包的两个类:Collections、Arrays 中,作为这两个类的静态方法提供给我们使用(直接用类名来引用,不用生成对象)。 从名字就可以看出来 Collections 提供的是基于集合类的算法, Arrays 提供的是基于数组的算法。java 中可以使用 Collecions 的 addAll 方法将数组添加到集合中:
import java.util.*;
public class Temp {
public static void main(String[] args) {
Integer[] A = { 5, 3, 1, 13, 8, 1, 2 };
LinkedList<Integer> C = new LinkedList<Integer>();
Collections.addAll(C, A);
// 集合类提供了 toString 方法可打印出所有元素
System.out.println(C);
}
}
二 sort
介绍了 copy 之后,再就介绍一个实实在在的算法—— 排序算法:
// C++ stl 排序
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
// 打印 begin 到 end 之间的所有数据
template<class InIt>
void displayAll(InIt begin, InIt end)
{
if(begin != end)
{
--end;
for(; begin!=end; ++begin)
cout<<*begin<<",";
cout<<*end;
}
cout<<endl;
}
// 求数组A的长度
#define LENGTH(A) (sizeof(A)/sizeof(A[0]))
int main()
{
int A[] = {5,3,1,13,8,1,2};
vector<int> C;
copy(A, A + LENGTH(A), inserter(C, C.end()));
// 给 vector 排序
displayAll(C.begin(), C.end());
sort(C.begin(), C.end());
displayAll(C.begin(), C.end());
cout<<"----------无情的分割线----------"<<endl;
// 给数组排序
displayAll(A, A + LENGTH(A));
sort(A, A + LENGTH(A));
displayAll(A, A + LENGTH(A));
return 0;
}
然后是 java 版,流程一样:
// java util 排序
import java.util.*;
public class Temp {
public static void main(String[] args) {
Integer[] A = { 5, 3, 1, 13, 8, 1, 2 };
LinkedList<Integer> C = new LinkedList<Integer>();
Collections.addAll(C, A);
// 给集合类排序
System.out.println(C);
Collections.sort(C);
System.out.println(C);
System.out.println("----------无情的分割线----------");
// 给数组排序
// 数组本身没有重写 toString 方法,但 Arrays 提供了
System.out.println(Arrays.toString(A));
Arrays.sort(A);
System.out.println(Arrays.toString(A));
}
}
C++ 中只有能随机访问的集合类能用 sort 排序,也就是说 vector 能排,list 不能排。而 java 中只要是实现了 List 接口的都能排(集合中元素需要实现 Comparable接口(比大小接口)), ArrayList 能排,LinkedList 也能排,从 sort 的源代码可以看到链表排序的真相:
所以链表的排序只是增加了 O(n) 量级的拷贝代价。
sort 会检查集合的规模以及是不是大部分已经有序,从而在 插入排序、归并排序、快速排序 中进行选择,所以它的性能还是很不错的。
三 其他算法
java 中还有一些常用的算法如:
- shuffle // 随机算法,将 List 集合打乱顺序。
- binarySearch // 二分查找算法
- reverse // 逆序算法
- min
- max
以上算法 C++ stl 中都有,C++ 还提供了如下算法:
- sort_heap // 堆排序
- stable_sort // 稳定排序
- nth_element // 找到第 n 大的数
当然,由于本猿也刚刚入门,还有很多提供了的算法没有用过,也就不提了。总之,多熟悉这些集合类、算法,少造车轮,总是好的。