C++中的数组类型是继承了c语言的特性,在使用数组的时候要注意数组越界操作问题。为了更安全的对数组进行操作,C++提出了数组模板类array。array内存空间为连续的一段地址,适用于提前已知所要存储的数据类型和数量、进行大量的查、改操作,不适用于含有大量交换、删除、增加数据的操作,该容器无法动态改变大小,所以说提前已知存储数据类型和数量。
1、array模板类的定义
array模板类的声明
template class array;
array模板类中T为包含元素的类型(std::array::value_type),N为元素个数。数组类是固定大小的序列容器,array 定义的时候必须定义数组的元素个数。除了需要指定元素的类型和个数之外,和常规数组没有太大的差别。显然不能增加或删除元素。
序列容器中的元素按严格的线性顺序排序。各个元素按其顺序访问它们的位置。元素存储在连续的存储器位置,允许对元素进行恒定时间随机访问。可以偏移元素的指针以访问其他元素。
使用array模板类之前需要包含#include
array a1 = {1 , 2 ,3 ,4 ,5};
array a2 = {0 , -1 , -2 , -3 , -5};
array a3 = {8, 9 , 10 , 11 , 22};
array , 3> a = {a1 , a2 , a3};
for(int i = 0 ; i < a.size() ; i++)
{
for(int j = 0 ; j < a[0].size() ; j++)
cout << a[i][j] << " ";
cout << endl;
}
2、array模板类的使用
(1)Iterators
Iterators迭代器的作用是遍历array数组类中的元素。可以通过begin/end()、rbegin/rend()、cbegin/cend()、crbegin/crend()等函数进行访问。
参考代码如下所示:
int main(void) {
array ad ;
std::array arr = {1, 2, 3, 4, 5};
std::cout << "array values: ";
for (auto it = arr.begin(); it != arr.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
运行结果如下所示:
array values: 1 2 3 4 5
(2)Capacity
array数组容器的大小是固定的。可以通过sizeof()、size()、max_size()、empty()等函数进行检测。
1、sizeof是一个操作符(operator)。返回一个对象或类型所占的内存字节数。
语法:sizeof有三种语法形式:
sizeof对对象求内存大小,最终都是转换为对对象的数据类型求值。sizeof (表达式); //值为表达式的最终结果的数据类型的大小。
int i;
sizeof(int); //值为4
sizeof(i); //值为4,等价于sizeof(int)
sizeof i; //值为4
sizeof(2); //值为4,等价于sizeof(int),因为2的类型为int
sizeof(2 + 3.14); //值为8,等价于sizeof(double),因为此表达式的结果的类型为double
更多内容:https://www.cnblogs.com/huolong-blog/p/7587711.html
2、size()返回数组的长度,即当前元素个数;
3、max_size()返回最大的可能的元素个数;
4、empty()检查数组是否为空,即有无元素存在。
参考代码如下所示:
int main(void) {
std::array arr = {1, 2, 3, 4, 5};
std::cout << "sizeof(array) = " << sizeof(arr) << std::endl;
std::cout << "size of array = " << arr.size() << std::endl;
std::cout << "max_size of array = " << arr.max_size() << std::endl;
if (arr.empty()) {
std::cout << "array is empty!" << std::endl;
} else {
std::cout << "array is not empty!" << std::endl;
}
return 0;
}
运行结果如下所示:
sizeof(array) = 20
size of array = 5
max_size of array = 5
array is not empty!
(3)访问方式
可以通过下标[ ]、at()、front()、back()、data()等函数访问array容器内的元素。
front 和back返回第一个和最后一个元素
data返回array的存放地址。
int main(void) {
std::array arr = {1, 2, 3, 4, 5};
std::cout << "array[0] = " << arr[0] << std::endl;
std::cout << "array.at(4) = " << arr.at(4) << std::endl;
std::cout << "array.front() = " << arr.front() << std::endl;
std::cout << "array.back() = " << arr.back() << std::endl;
std::cout << "&array: " << arr.data() << " = " << &arr << std::endl;
return 0;
}
运行结果如下所示:
array[0] = 1
array.at(4) = 5
array.front() = 1
array.back() = 5
&array: 0x7ffd22df6e50 = 0x7ffd22df6e50
(4)Modifiers
1、通过调用数组对象的成员函数 fill(),可以将所有元素设成给定值。例如:
values.fill(3.1415926);
2、swap()函数用于将两个array互换:
std::array first = {1, 2, 3};
std::array second = {6, 5, 4};
first.swap(second); // swap
first : 1 2 3
second : 6 5 4
swap:
first : 6 5 4
second : 1 2 3
(5)Compare
可以使用> < == 等符号对两个array数组容器进行比较。比较时采用逐个元素进行比较。
from :https://blog.csdn.net/zhengqijun_/article/details/81566109
STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。STL中的容器有队列容器和关联容器,容器适配器(congtainer adapters:stack,queue,priority queue),位集(bit_set),串包(string_package)等等。
(1)序列式容器(Sequence containers),每个元素都有固定位置--取决于插入时机和地点,和元素值无关,vector、deque、list;
Vector:将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时;
Deque:是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速。但是在中部或头部安插元素比较费时;
List:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针;
(2)关联式容器(Associated containers),元素位置取决于特定的排序准则,和插入顺序无关,set、multiset、map、multimap等。
Set/Multiset:内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,Multisets内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
Map/Multimap:Map的元素是成对的键值/实值,内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
容器类自动申请和释放内存,无需new和delete操作。
vector 是向量类型,它可以容纳许多类型的数据,如若干个整数,所以称其为容器。看成是一种可以存放各种类型对象的容器,简单地说,vector是一个能够存放任意类型的动态数组。vector 是C++ STL的一个重要成员,使用它时需要包含头文件:
#include;
有五种方式,举例说明如下:
vector a(10); //定义了10个整型元素的向量(尖括号中为元素类型名),但没有给出初值,其值是不确定的。
vector a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
vector a(b); //用b向量来创建a向量,整体复制性赋值
vector a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
int b[7]={1,2,3,4,5,9,8};
vector a(b,b+7); //从数组中获得初值
1、通过下标“[]”读取
int a[6]={1,2,3,4,5,6};
vector b(a,a+4);
for(int i=0;i<=b.size()-1;i++)
cout<
2、通过遍历器方式读取
int a[6]={1,2,3,4,5,6};
vector b(a,a+4);
for(vector::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
3、访问首尾元素
a.back(); //返回a的最后一个元素
a.front(); //返回a的第一个元素
1、直接将元素添加入vector
vector a;
for(int i=0;i<10;i++)
a.push_back(i);
2、也可以从数组中选择元素,向vector中添加
int a[6]={1,2,3,4,5,6};
vector b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);
3、也可以从现有向量中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector b;
vector c(a,a+4);
for(vector::iterator it=c.begin();it
4、【误区】不能用下面这种做法对其进行赋值。下标只能用于获取已存在的元素,而现在的a[i]还是空的对象。
vector a;
a[i]=9;
但是可以使用这种方法对齐进行修改元素:
vector vec; // []
vec.push_back(1); // [1]
vec.push_back(2); // [1, 2]
vec.push_back(3); // [1, 2, 3]
vec[1] = 3; // [1, 3, 3]
vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
1、pop_back,从尾部删除
a.pop_back(); //删除a向量的最后一个元素
2、删除a中第0个到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
a.erase(a.begin()+1,a.begin()+3);
insert() 函数有以下三种用法:
1、v=2 7 9,在最前面插入一个8后,向量元素为:8 2 7 9 3
v.insert(v.begin(),8);//在最前面插入新元素。
v.insert(v.end(),3);//在向量末尾追加新元素。
2、在a的第2个元素前插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
a.insert(a.begin()+1,5);
3、在a的第2个元素前,插入3个数,其值都为5
a.insert(a.begin()+1,3,5);
4、b为数组,在a的第2个元素前插入b的第3个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
a.size(); //返回a中元素的个数;
a.capacity(); //返回a在内存中总共可以容纳的元素个数
a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
a.assign(4,2); //是a只含4个元素,且每个元素为2
a.clear(); //清空a中的元素
a.empty(); //判断a是否为空,空则返回ture,不空则返回false
a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.
a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
使用时需要包含头文件:#include
1、对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
2、对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
3、把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
4、在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
sort(a.begin(),a.end());
reverse(a.begin(),a.end());
copy(a.begin(),a.end(),b.begin()+1);
find(a.begin(),a.end(),10);
list 是顺序容器的一种。list 是一个双向链表。使用 list 需要包含头文件。与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢,双向链表的每个元素中都有一个指针指向后一个元素,也有一个指针指向前一个元素。
双向链表的节点包括:
struct DNode{
int value;
DNode * left;
DNode * right;
};
在list容器中,在已经定位到要增删元素的位置的情况下,增删元素能在常数时间内完成。在 和之间插入一个元素,只需要修改和中的指针即可。
图:在双向链表中插入元素
list 容器不支持根据下标随机存取元素。
1、List定义和初始化:
listlst1; //创建空list
list lst2(5); //创建含有5个元素的list
listlst3(3,2); //创建含有3个元素的list
listlst4(lst2); //使用lst2初始化lst4
listlst5(lst2.begin(),lst2.end()); //同lst4
2、遍历List
//迭代器法
for(list::const_iteratoriter = lst1.begin();iter != lst1.end();iter++)
cout<<*iter<
//
for (it = mylist.begin(); it != mylist.end(); ++i)
cout << *it << " ";
3、push_back() 和push_front():
使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。
listOne.push_front(3);
listOne.push_front(2);
listOne.push_front(1);
listOne.push_back(4);
listOne.push_back(5);
listOne.push_back(6);
for(list::iterator it=listOne.begin();it!=listOne.end();++it)
cout<<*it<<" ";
输出:1 2 3 4 5 6
4、 empty():利用empty() 判断list是否为空。
5、 resize():调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除。
6 clear(): 清空list中的所有元素。
7 front()和back():
通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,调用front()和back()并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。
8 pop_back和pop_front():
通过pop_back()删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
9 assign()
具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。
10 swap():交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。
11 reverse():通过reverse()完成list的逆置。
12 merge():
合并两个链表并使之默认升序(也可改),l1.merge(l2,greater
13 insert():在指定位置插入一个或多个元素(三个重载):
14 erase():删除一个元素或一个区域的元素(两个重载)
from:https://blog.csdn.net/u011630575/article/details/79734358
from:https://blog.csdn.net/Richard__Ting/article/details/79490665
单链表node的数据结构定义如下:
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
单链表的反转是常见的面试题目:
思路:把当前链表的下一个节点pCur插入到头结点dummy的下一个节点中,就地反转。
dummy->1->2->3->4->5:
dummy->2->1->3->4->5
dummy->3->2->1->4->5
dummy->4>-3->2->1->5
dummy->5->4->3->2->1
pCur:需要反转的节点。
循环条件:pCur is not null
prev.next = pCur.next;
pCur.next = dummy.next;
dummy.next = pCur;
pCur = prev.next;
。。。。
// 1.就地反转法
public ListNode reverseList1(ListNode head) {
if (head == null)
return head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode prev = dummy.next;
ListNode pCur = prev.next;
while (pCur != null) {
prev.next = pCur.next;
pCur.next = dummy.next;
dummy.next = pCur;
pCur = prev.next;
}
return dummy.next;
}
from: https://www.cnblogs.com/byrhuangqiang/p/4311336.html
更多参见Python学习:https://blog.csdn.net/qq_30815237/article/details/90750349