迭代器(Iterator)
迭代器是 C++ 的知识,并不适用于 Java 和 Python 这两种语言。迭代器的知识点很复杂,实现方式看容器讲解。
对于数组我们可以采用指针进行访问,但是对于其他的存储空间连续的数据结构或者说是存储单元我们就需要找到另一种方式来替代指针的行为作用,从而达到对于非数组的数据结构的访问和遍历,于是我们定义了一种新的变量叫做迭代器。
定义:
迭代器是一种检查容器内元素并遍历元素的数据类型。
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。
迭代器和指针的区别:
容器和 string 有迭代器类型同时拥有返回迭代器的成员。
如:容器有成员 .begin() 和 .end(),其中 .begin() 成员复制返回指向第一个元素的迭代器,即指向第一个元素的“地址”,而 .end() 成员返回指向容器尾元素的下一个位置的迭代器。
即 .begin() 指向的是第一个合法元素的位置,.end() 指向是容器后第一个不合法元素的地址。
相应的还有容器反向迭代器成员 .rbegin() .rend(), .rbegin() 返回容器的元素前最后一个不合法的地址,rend() 返回容器的最后一个合法地址。
容器迭代器的使用
每种容器类型都定义了自己的迭代器类型.
数据类型是由 vector< int> 定义的 iterator 类型。简单说就是容器类定义了自己的 iterator 类型,用于访问容器内的元素。每个容器定义了一种名为 iterator 的类型,这种类型支持迭代器的各种行为。
容器
在 Java 中各种数据结构都是继承于 list,所以 Java 的 list 功能很强,它的功能有很多。
Vector 容器(类)
线性表中有 Vector 和 list,两者作用比较相似。
Vector 的主要作用就是可变长度的数组,就把他当成数组使用即可。
java 的实现方式:
//第一种构造方法创建一个默认的向量,默认大小为 10:
Vector()
//第二种构造方法创建指定大小的向量。
Vector(int size)
//第三种构造方法创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目。
Vector(int size,int incr)
//第四种构造方法创建一个包含集合 c 元素的向量:
Vector(Collection c)
以下为 Java Vector 的 API。
修饰符和类型 | 方法和说明 |
---|---|
boolean | add(E e)将指定的元素附加到此 Vector 的末尾。 |
void | add(int index, E element)在此 Vector 的指定位置插入指定元素。 |
boolean | addAll(Collection<? extends E> c)将指定集合中的所有元素追加到末尾 这个向量,按照它们由指定的返回的顺序 集合的迭代器。 |
boolean | addAll(int index, Collection<? extends E> c)将指定 Collection 中的所有元素插入到此 指定位置的向量。 |
void | addElement(E obj)将指定的组件添加到此向量的末尾, 将其大小增加一。 |
int | capacity()返回此向量的当前容量。 |
void | clear()从此 Vector 中删除所有元素。 |
Object | clone()返回此向量的克隆。 |
boolean | contains(Object o)退货 true 如果此向量包含指定的元素。 |
boolean | containsAll(Collection<?> c)如果此 Vector 包含所有元素,则返回 true 指定的集合。 |
void | copyInto(Object[] anArray)将此向量的分量复制到指定的数组中。 |
E | elementAt(int index)返回指定索引处的组件。 |
Enumeration | elements()返回此向量的组件的枚举。 |
void | ensureCapacity(int minCapacity)如有必要,增加此向量的容量,以确保它至少可以容纳由指定的组件数量最小容量参数。 |
boolean | equals(Object o)比较指定的 Object 与此 Vector 是否相等。 |
E | firstElement()返回第一个组件(索引处的项目 0) 的这个向量。 |
E | get(int index)返回此 Vector 中指定位置的元素。 |
int | hashCode()返回此 Vector 的哈希码值。 |
int | indexOf(Object o)返回指定元素第一次出现的索引 在此向量中,如果此向量不包含该元素,则为 -1。 |
int | indexOf(Object o,int index)返回指定元素第一次出现的索引这个向量,从 index, 或返回 -1 如果 未找到该元素。 |
void | insertElementAt(E obj, int index)将指定对象作为组件插入此向量中的 指定的 index. |
boolean | isEmpty()测试此向量是否没有组件。 |
Iterator | iterator()以适当的顺序返回此列表中元素的迭代器 |
E | lastElement()返回向量的最后一个组件。 |
int | lastIndexOf(Object o)返回指定元素最后一次出现的索引在此向量中,如果此向量不包含该元素,则为 -1。 |
int | lastIndexOf(Object o, int index)返回指定元素最后一次出现的索引这个向量,从 index, 或返回 -1 如果 未找到该元素。 |
ListIterator | listIterator()返回此列表中元素的列表迭代器(在适当的顺序)。 |
ListIterator | listIterator(int index)返回此列表中元素的列表迭代器(在适当的序列),从列表中的指定位置开始。 |
E | remove(int index)移除此 Vector 中指定位置的元素。 |
boolean | remove(Object o)移除此 Vector 中第一次出现的指定元素如果 Vector 不包含该元素,则它保持不变。 |
boolean | removeAll(Collection<?> c)从此 Vector 中删除其包含在指定的集合。 |
void | removeAllElements()从此向量中删除所有组件并将其大小设置为零。 |
boolean | removeElement(Object obj)删除参数的第一个(最低索引)出现从这个向量。 |
void | removeElementAt(int index)删除指定索引处的组件。 |
protected void | removeRange(int fromIndex, int toIndex)从此列表中删除索引介于两者之间的所有元素 fromIndex,包括在内,和 toIndex, 独家的。 |
boolean | retainAll(Collection<?> c)仅保留此 Vector 中包含在指定的集合。 |
E | set(int index, E element)将此 Vector 中指定位置的元素替换为指定的元素。 |
void | setElementAt(E obj,int index)将组件设置在指定的位置 index 这个的向量是指定的对象。 |
void | setSize(int newSize)设置此向量的大小。 |
int | size()返回此向量中的组件数。 |
List | subList(int fromIndex,int toIndex)返回此列表中 fromIndex 之间的部分的视图 |
Object[] | toArray()返回一个包含此 Vector 中所有元素的数组以正确的顺序。 |
T[] | toArray(T[] a)返回一个包含此 Vector 中所有元素的数组正确的顺序; 返回数组的运行时类型指定数组。 |
String | toString()返回此 Vector 的字符串表示形式,包含 每个元素的字符串表示。 |
void | trimToSize()将此向量的容量修剪为向量的电流 尺寸。 |
遍历 Vector
Enumeration vEnum = v.elements();
while (vEnum.hasMoreElements())
System.out.print(vEnum.nextElement() + " ");
快递的分拣
快递员需要对快递进行分拣,现在小李是一名快递员,他想要你帮他设计一个程序用于快递的分拣,按城市分开。
现在有以下输入:
单号 省份 请你将单号按照城市分开,并输出。 城市按照输入顺序排序 单号按照输入顺序排序
样例如下:
输入
10
10124214 北京
12421565 上海
sdafasdg213 天津
fasdfga124 北京
145252 上海
235wtdfsg 济南
3242356fgdfsg 成都
23423 武汉
23423565f 沈阳
1245dfwfs 成都
输出
北京 2
10124214
fasdfga124
上海 2
12421565
145252
天津 1
sdafasdg213
济南 1
235wtdfsg
成都 2
3242356fgdfsg
1245dfwfs
武汉 1
23423
沈阳 1
23423565f
首先我们要知道中国城市肯定在 1000 个以内,但是单号我们不确定,我们不可能每个数组开 10000 个,那样内存不够,所以这时候我们就用到了我们的 vector,他的容量是动态申请的,在比赛中我们可以理解为无限制。
- 第一步:我们创建一个 vector 用于保存地址
static Vector city=new Vector<String>();
- 第二步:我们创建一个 vector 组用于存放单号
static Vector <Vector<String>> dig= new Vector <Vector<String>>();
注意: city是一个表,dig是一堆表。city里每一个下标都代表不同的城市,且每个下标都能再dig中找到对应的表,而dig中所对应的表用来存放对应的单号。
-
第三步:我们定义一个映射函数,因为你的城市可能会再次出现,你需要知道之前有没有。
当我们输入城市字符串时需要了解city表里有没有,没有就用addElement(E obj)将城市字符串添加到city的末尾, 将其大小增加一,如果有就返回下标,利用返回的下标在dig中找到对应的表把单号存放进去。
-
第四步:我们开始读入操作并按照顺序进行存放
dig中存放存放单号时要注意dig的下标是[city.size()-1]。因为city开始存元素时size为1,下标为0.即city[i]的i是从0开始,而city.size()是从1开始。同样的dig[i]的i也是从0 开始,所以需要city.size()-1。
完整代码
import java.util.List;
import java.util.Scanner;
import java.util.Vector;
public class Main {
static Vector city=new Vector<String>();
static Vector <Vector<String>> dig= new Vector <Vector<String>>();
static int Myfind(String s)
{//判断这个城市有没有出现过,如果有就返回它的下标
for(int i=0;i<city.size();i++)
{
if(city.get(i).equals(s)) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
int n;
Scanner in=new Scanner(System.in);
n=in.nextInt();
for(int i=0;i<n;i++)
{
String d,c;
d=in.next();
c=in.next();
int flag=Myfind(c);
if(flag==-1){//如果不存在那就再city里创建一个
city.addElement(c);//addElement(E obj)将指定的组件添加到此向量的末尾, 将其大小增加一。
dig.addElement(new Vector<String>());
dig.get(city.size()-1).addElement(d);//当city开始存东西时.size()是1,但是city的下标是0.
}
else dig.get(flag).addElement(d);//存在便返回它的下标再dig里找到,并把单号放进去
}
for(int i=0;i<city.size();i++)
{
System.out.println(city.get(i)+" "+dig.get(i).size());
for(int j = 0; j< dig.get(i).size(); j++)
System.out.println(dig.get(i).get(j));
}
}
}
队列 Queue
Java 中的队列
定义方式:
Queue<String> queue = new LinkedList<String>();
部分成员函数(包括继承的):
- add(): 增加一个元索,如果队列已满,则抛出一个异常
- remove():移除并返回队列头部的元素,如果队列为空,则抛出一个异常
- element():返回队列头部的元素,如果队列为空,则抛出一个异常
- offer():添加一个元素并返回 true,如果队列已满,则返回 false
- poll(): 移除并返问队列头部的元素,如果队列为空,则返回 null
- peek(): 返回队列头部的元素,如果队列为空,则返回 null
- put(): 添加一个元素, 如果队列满,则阻塞
- take(): 移除并返回队列头部的元素,如果队列为空,则阻塞
- size(): 返回队列长度。
CLZ 的银行。
第一行 M 次操作(M<1000)
第二行 到 第M+1行 输入操作
格式: IN name V
OUT V
IN name2 N
OUT N
即 第一个字符串为操作 是IN进入排队和OUT 出队
IN 排队 跟着两个字符串为姓名和权限V或N
OUT 为出队即完成操作,V和N代表那个窗口完成了操作
输出:M次操作后V队列和N队列中姓名,先输出V队列后输出N队列。
样例:
输入:
5
IN xiaoming N
IN Adel V
IN laozhao N
OUT N
IN CLZ V
输出:
Adel
CLZ
laozhao
借此题了解一下预置代码的方便性。
完整代码
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static Queue<String> V=new LinkedList<String>();
static Queue<String> N=new LinkedList<String>();
public static void main(String[] args) {
int M;
Scanner in=new Scanner(System.in);
M=in.nextInt();
while(M>0) //
{
M--;
String op,name,type;
op=in.next();
// System.out.println("op"+op);
if(op.contains("IN"))
{
name=in.next();
type=in.next();
if(type.contains("V")) {
V.offer(name);//offer():添加一个元素并返回 true,如果队列已满,则返回 false
}
else {
N.offer(name);
}
// System.out.println("name:"+name+"type:"+type);
// System.out.println(Vqueue);
}
else
{
type=in.next();
if(type.contains("V")){
V.poll();
}
else {
N.poll();
}
// System.out.println("type"+type);
}
}
while(V.size()!=0)
{
System.out.println(V.poll());
}
while(N.size()!=0)
{
System.out.println(N.poll());
}
}
}
Map 映射
map 是一个关联容器,它提供一对一的 hash。
- 第一个可以称为关键字(key),每个关键字只能在 map 中出现一次
- 第二个可称为该关键字的值(value)
map 以模板(泛型)方式实现,可以存储任意类型的数据,包括使用者自定义的数据类型。Map 主要用于资料一对一映射的情況,在 map 内部所有的数据都是有序的。
比如,像是管理班级内的学生,Key 值为学号,Value 放其他信息的结构体或者类。
Java 中的 map
定义方法:
Map m1 = new TreeMap();
java里的有序map是Treemap,不排序的map是Hashmap,如果不需要排序可以直接使用。
成员方法
方法名 | 方法描述 |
---|---|
void clear( ) | 从此映射中移除所有映射关系(可选操作)。 |
boolean containsKey(Object k) | 如果此映射包含指定键的映射关系,则返回 true。 |
boolean containsValue(Object v) | 如果此映射将一个或多个键映射到指定值,则返回 true。 |
boolean equals(Object obj) | 比较指定的对象与此映射是否相等。 |
Object get(Object k) | 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 |
int hashCode( ) | 返回此映射的哈希码值。 |
boolean isEmpty( ) | 如果此映射未包含键-值映射关系,则返回 true。 |
Set keySet( ) | 返回此映射中包含的键的 Set 视图。 |
Object put(Object k, Object v) | 将指定的值与此映射中的指定键关联 |
Object remove(Object k) | 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 |
int size( ) | 返回此映射中的键-值映射关系数。 |
Collection values( ) | 返回此映射中包含的值的 Collection 视图。 |
弗里石的的语言
小发明家弗里想创造一种新的语言,众所周知,发明一门语言是非常困难的,首先你就要克服一个困难就是,有大量的单词需要处理,现在弗里求助你帮他写一款程序,判断是否出现重复的两个单词。
有重复就输出重复单词,重复就输出 NO,多个重复输出最先出现的哪一个。
输入:
第 1 行,输入N,代表共计创造了多少个单词
第 2 行至第 N+1 行,输入 N 个单词
格式:
fjsdfgdfsg
fdfsgsdfg
bcvxbxfyres
现在有以下样例输入:
样例 1
输入:
6
1fagas
dsafa32j
lkiuopybncv
hfgdjytr
cncxfg
sdhrest
输出:
NO
样例 2
输入:
5
sdfggfds
fgsdhsdf
dsfhsdhr
sdfhdfh
sdfggfds
输出:
sdfggfds
这里使用映射和字典解题
代码如下:
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class Main {
static Map mp=new TreeMap();
public static void main(String[] args)
{
int n;
boolean flag=false;
Scanner in=new Scanner(System.in);
String ans="NO";
n=in.nextInt();
for(int i=0;i<n;i++)
{
String word;
word=in.next();
// System.out.println(Hx(word));
if(flag) continue;
if(mp.containsKey(word)){//boolean containsKey(Object k) 如果此映射包含指定键的映射关系,则返回 true。
flag=true;
ans=word;
}
else {
mp.put(word,true);//Object put(Object k, Object v) 将指定的值与此映射中的指定键关联
}
}
System.out.println(ans);
}
}