在JAVA中/vector
基本简介
Java.util.Vector提供了向量(Vector)类以实现类似动态数组的功能。在Java语言中是没有指针概念的,但如果能正确灵活地使用指针又确实可以大大提高程序的质量,比如在C、C++中所谓“动态数组”一般都由指针来实现。为了弥补这点缺陷,Java提供了丰富的类库来方便编程者使用,Vector类便是其中之一。事实上,灵活使用数组也可完成向量类的功能,但向量类中提供的大量方法大大方便了用户的使用。
相对于ArrayList来说,Vector线程是安全的,也就是说是同步的
创建了一个向量类的对象后,可以往其中随意地插入不同的类的对象,既不需顾及类型也不需预先选定向量的容量,并可方便地进行查找。对于预先不知或不愿预先定义数组大小,并需频繁进行查找、插入和删除工作的情况,可以考虑使用向量类。向量类提供了三种构造方法:
publicvector()
publicvector(intinitialcapacity,intcapacityIncrement)
publicvector(intinitialcapacity)
使用*种方法,系统会自动对向量对象进行管理。若使用后两种方法,则系统将根据参数initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时,系统会扩充向量对象的存储容量。
参数capacityIncrement给定了每次扩充的扩充值。当capacityIncrement为0时,则每次扩充一倍。利用这个功能可以优化存储。在Vector类中提供了各种方法方便用户使用:
插入功能
(1)publicfinalsynchronizedvoidaddElement(Objectobj)
将obj插入向量的尾部。obj可以是任何类的对象。对同一个向量对象,可在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数值转换成相应的对象。
例要插入一个整数1时,不要直接调用v1.addElement(1),正确的方法为:
Vectorv1=newVector();
Integerinteger1=newInteger(1);
v1.addElement(integer1);
(2)publicfinalsynchronizedvoidsetElementAt(objectobj,intindex)
将index处的对象设成obj,原来的对象将被复盖。
(3)publicfinalsynchronizedvoidinsertElementAt(Objectobj,intindex)
在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。
删除功能
(1)publicfinalsynchronizedvoidremoveElement(Objectobj)
从向量中删除obj。若有多个存在,则从向量头开始试,删除找到的*与obj相同的向量成员。
(2)publicfinalsynchronizedvoidremoveAllElement()
删除向量中所有的对象。
(3)publicfinalsynchronizedvoidremoveElementlAt(intindex)
删除index所指的地方的对象。
查询搜索
(1)publicfinalintindexOf(Objectobj)
从向量头开始搜索obj,返回所遇到的*obj对应的下标,若不存在此obj,返回-1。
(2)publicfinalsynchronizedintindexOf(Objectobj,intindex)
从index所表示的下标处开始搜索obj。
(3)publicfinalintlastIndexOf(Objectobj)
从向量尾部开始逆向搜索obj。
(4)publicfinalsynchronizedintlastIndexOf(Objectobj,intindex)
从index所表示的下标处由尾至头逆向搜索obj。
(5)publicfinalsynchronizedObjectfirstElement()
获取向量对象中的*obj。
(6)publicfinalsynchronizedObjectlastelement()
获取向量对象中的较后一个obj。
举例说明
了解了向量的最基本的方法后,我们来看一下例子VectorApp.java。
例VectorApp.java
importjava.util.Vector;
importjava.lang.*;
//这一句不应该要,但原文如此
importjava.util.Enumeration;
publicclassVectorApp
{
publicstaticvoidmain(String[]args)
{
Vectorv1=newVector();
Integerinteger1=newInteger(1);
v1.addElement(one);
//加入的为字符串对象
v1.addElement(integer1);
v1.addElement(integer1);
//加入的为Integer的对象
v1.addElement(two);
v1.addElement(newInteger(2));
v1.addElement(integer1);
v1.addElement(integer1);
System.out.println(Thevectorv1is:nt+v1);
//将v1转换成字符串并打印
v1.insertElementAt(three,2);
v1.insertElementAt(newFloat(3.9),3);
System.out.println(Thevectorv1(usedmethodinsertElementAt())is:nt+v1);
//往指定位置插入新的对象,指定位置后的对象依次往后顺延
v1.setElementAt(four,2);
System.out.println(Thevectorv1(usedmethodsetElementAt())is:nt+v1);
//将指定位置的对象设置为新的对象
v1.removeElement(integer1);
//从向量对象v1中删除对象integer1由于
存在多个integer1所以从头开始
找,删除找到的*integer1
Enumerationenum=v1.elements();
System.out.print(Thevectorv1(usedmethodremoveElement())is:);
while(enum.hasMoreElements())
System.out.print(enum.nextElement()+);
System.out.println();
//使用枚举类(Enumeration)的方法来获取向量对象的每个元素
System.out.println(Thepositionofobject1(top-to-bottom):
+v1.indexOf(integer1));
System.out.println(Thepositionofobject1(tottom-to-top):
+v1.lastIndexOf(integer1));
//按不同的方向查找对象integer1所处的位置
v1.setSize(4);
System.out.println(Thenewvector(resizedthevector)is:+v1);
//重新设置v1的大小,多余的元素被行弃
}
}
运行结果:
E:java01>javaVectorApp
Thevectorv1is:
[one,1,1,two,2,1,1]
Thevectorv1(usedmethodinsertElementAt())is:
[one,1,three,3.9,1,two,2,1,1]
Thevectorv1(usedmethodsetElementAt())is:
[one,1,four,3.9,1,two,2,1,1]
Thevectorv1(usedmethodremoveElement())is:
onefour3.91two211
Thepositionofobject1(top-to-bottom):3
Thepositionofobject1(tottom-to-top):7
Thenewvector(resizedthevector)is:
[one,four,3.9,1]
E:java01>
从例1中运行的结果中可以清楚地了解上面各种方法的作用,另外还有几点需解释。
(1)类Vector定义了方法
publicfinalintsize()
此方法用于获取向量元素的个数。它的返回值是向是中实际存在的元素个数,而非向量容量。可以调用方法capactly()来获取容量值。
方法:
publicfinalsynchronizedvoidsetsize(intnewsize)
此方法用来定义向量大小。若向量对象现有成员个数已超过了newsize的值,则超过部分的多余元素会丢失。
(2)程序中定义了Enumeration类的一个对象
Enumeration是java.util中的一个接口类,在Enumeration中封装了有关枚举数据集合的方法。
在Enumeration中提供了方法hawMoreElement()来判断集合中是否还有其它元素和方法nextElement()来获取下一个元素。利用这两个方法可以依次获得集合中元素。
Vector中提供方法:
publicfinalsynchronizedEnumerationelements()
此方法将向量对象对应到一个枚举类型。java.util包中的其它类中也大都有这类方法,以便于用户获取对应的枚举类型。
详细说明/vector
vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。
和string对象一样,标准库将负责管理与存储元素相关的内存。我们把vector称为容器,是因为它可以包含其他对象,能够存放任意类型的动态数组,增加和压缩数据。一个容器中的所有对象都必须是同一种类型的。
vector是一个类模板(classtemplate)。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。因此,我们可以定义保存string对象的vector,或保存int值的vector,又或是保存自定义的类类型对象(如Sales_items对象)的vector。vector不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector类型的每一种都指定了其保存元素的类型。
为了可以使用vector,必须在你的头文件中包含下面的代码:
#include<vector>
vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:
usingstd::vector;
vector<int>vInts;
或者连在一起,使用全名:
std::vector<int>vInts;
建议在代码量不大,并且使用的命名空间不多的情况下,使用全局的命名域方式:usingnamespacestd;
函数
表述
c.assign(beg,end)c.assign(n,elem)
将(beg;end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。
传回索引idx所指的数据,如果idx越界,抛出out_of_range。
c.back()
传回较后一个数据,不检查这个数据是否存在。
c.begin()
传回迭代器中的*数据地址。
c.capacity()
返回容器当前已分配的容量。
c.clear()
移除容器中所有数据。
c.empty()
判断容器是否为空。
c.end()//指向迭代器中末端元素的下一个,指向一个不存在元素。
c.erase(pos)//删除pos位置的数据,传回下一个数据的位置。
c.erase(beg,end)
删除[beg,end)区间的数据,传回下一个数据的位置。
c.front()
传回*数据。
get_allocator
使用构造函数返回一个拷贝。
c.insert(pos,elem)//在pos位置插入一个elem拷贝,传回新数据位置
c.insert(pos,n,elem)//在pos位置插入n个elem数据,无返回值
c.insert(pos,beg,end)//在pos位置插入在[beg,end)区间的数据。无返回值
c.max_size()
返回容器中*数据的数量。
c.pop_back()
删除较后一个数据。
c.push_back(elem)
在尾部加入一个数据。
c.rbegin()
传回一个逆向队列的*数据。
c.rend()
传回一个逆向队列的较后一个数据的下一个位置。
c.resize(num)
重新指定队列的长度。
c.reserve()
保留适当的容量。
c.size()
返回容器中实际数据的个数。
c1.swap(c2)//将c1和c2元素互换
swap(c1,c2)//同上操作。
vector<Elem>//创建一个空的vector
vector<Elem>c1(c2)//复制一个vector
vector<Elem>c(n)//创建一个vector,含有n个数据,数据均已缺省构造产生
vector<Elem>c(n,elem)//创建一个含有n个elem拷贝的vector
vector<Elem>c(beg,end)//创建一个以(beg;end)为区间的vector
c.~vector()//销毁所有数据,释放内存
operator[]
返回容器中指定位置的一个引用。
创建一个vector
vector容器提供了多种创建方法,下面介绍几种常用的。
创建一个Widget类型的空的vector对象:
vector<Widget>vWidgets;
创建一个包含500个Widget类型数据的vector:
vector<Widget>vWidgets(500);
创建一个包含500个Widget类型数据的vector,并且都初始化为0:
vector<Widget>vWidgets(500,Widget(0));
创建一个Widget的拷贝:
vector<Widget>vWidgetsFromAnother(vWidgets);
向vector添加一个数据
vector添加数据的缺省方法是push_back()。push_back()函数表示将数据添加到vector的尾部,并按需要来分配内存。例如:向vector<Widget>;中添加10个数据,需要如下编写代码:
for(inti=0;i<10;i++){
vWidgets.push_back(Widget(i));
}
获取vector中指定位置的数据
vector里面的数据是动态分配的,使用push_back()的一系列分配空间常常决定于文件或一些数据源。如果想知道vector是否为空,可以使用empty(),空返回true,否则返回false。获取vector的大小,可以使用size()。例如,如果想获取一个vectorv的大小,但不知道它是否为空,或者已经包含了数据,如果为空时想设置为-1,你可以使用下面的代码实现:
intnSize=v.empty()?-1:static_cast<int>(v.size());
访问vector中的数据
使用两种方法来访问vector。
1、vector::at()
2、vector::operator[]
operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的*,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所以我们很少用它.
删除vector中的数据
vector能够非常容易地添加数据,也能很方便地取出数据,同样vector提供了erase(),pop_back(),clear()来删除数据,当删除数据时,应该知道要删除尾部的数据,或者是删除所有数据,还是个别的数据。
remove()算法如果要使用remove,需要在头文件中包含如下代码:
#include<algorithm>
remove有三个参数:
1、iterator_First:指向*数据的迭代指针。
2、iterator_Last:指向较后一个数据的迭代指针。
3、predicate_Pred:一个可以对迭代操作的条件函数。
条件函数
条件函数是一个按照用户定义的条件返回是或否的结果,是最基本的函数指针,或是一个函数对象。这个函数对象需要支持所有的函数调用操作,重载operator()()操作。remove是通过unary_function继承下来的,允许传递数据作为条件。
例如,假如想从一个vector<CString>;中删除匹配的数据,如果字串中包含了一个值,从这个值开始,从这个值结束。首先应该建立一个数据结构来包含这些数据,类似代码如下:
#include<functional>
enumfindmodes{
FM_INVALID=0,
FM_IS,
FM_STARTSWITH,
FM_ENDSWITH,
FM_CONTAINS
};
typedefstructtagFindStr{
UINTiMode;
CStringszMatchStr;
}FindStr;
typedefFindStr*LPFINDSTR;
然后处理条件判断:
classFindMatchingString:publicstd::unary_function<CString,bool>{
public:
FindMatchingString(constLPFINDSTRlpFS):
m_lpFS(lpFS){
}
booloperator()(CString&szStringToCompare)const{
boolretVal=false;
switch(m_lpFS->iMode){
caseFM_IS:{
retVal=(szStringToCompare==m_lpFDD->szMatchStr);
break;
}
caseFM_STARTSWITH:{
retVal=(szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())
==m_lpFDD->szWindowTitle);
break;
}
caseFM_ENDSWITH:{
retVal=(szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())
==m_lpFDD->szMatchStr);
break;
}
caseFM_CONTAINS:{
retVal=(szStringToCompare.Find(m_lpFDD->szMatchStr)!=-1);
break;
}
}
returnretVal;
}
private:
LPFINDSTRm_lpFS;
};
通过这个操作你可以从vector中有效地删除数据:
FindStrfs;
fs.iMode=FM_CONTAINS;
fs.szMatchStr=szRemove;
vs.erase(std::remove_if(vs.begin(),vs.end(),FindMatchingString(&fs)),vs.end());
Remove(),remove等所有的移出操作都是建立在一个迭代范围上的,不能操作容器中的数据。所以在使用remove,实际上操作的时容器里数据的上面的。
看到remove实际上是根据条件对迭代地址进行了修改,在数据的后面存在一些残余的数据,那些需要删除的数据。剩下的数据的位置可能不是原来的数据,但他们是不知道的。
调用erase()来删除那些残余的数据。注意上面例子中通过erase()删除remove的结果和vs.enc()范围的数据。
常见错误:
nomatchingfunctionforcallto‘std::vector,一般由定义的类型与存入的类型不匹配引起。