首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

一道百度机器学习工程师职位的面试题

题目:现在有 a 到 z 26 个元素, 编写程序打印 a 到 z 中任取 3 个元素的组合(比如 打印 a b c ,d y z等) 分析: 大家看看我这么做行不 char a, b, c; for(a = 'a'; a<='z'; a++) for(b= a+1; b<='z'; b++) for(c = b+1; c<='z'; c++) printf("%c%c%c\n", a, b, c); 问题1:不可能出现 bac等。因为每次我多加了 1 看看嵌套的 for 有什么不同,但是题目要求只求组合不管顺序。 问题2:如果你要这么做 ,面试官必然会问 ,如果我要求 4 个字母的组合呢?(一脸懵逼状=。=) 思路: 我设想 a - z 每个字母给一个标记 0 或 1 ,如果为 1 的时候表示这个字符在组合中 ,如果为 0 那么表示这个字符不在组合中。 这样子,我们需要 26 个标记位。 这个时候我们会发现 ,当所有变量都在组合中时, 那么就是 26 个 1;当一个变量都不在集组合中时,就是 26 个 0。 我们把 26 个 1 和 26 个 0 看成数字,那么就是 0 和 (1 << 26) - 1。 那么其它的组合,肯定是 0 到 (1 << 26) - 1 之间的数字,对吧 比如 cba 就是 ...0000000111 dcba 就是 ...00000000001111 所以说 我们做一个循环 从 0 开始 到(1 << 26) - 1 然后只取有 3 个 1 的数字 然后再看对应的 1 代表哪个字符就可以了 具体就要看程序了: #include <stdio.h> //某个数二进制位上有几个 1 int bit(unsigned int x) { int c = 0; while( x ) { c++; x = (x & (x - 1)); } return c; } void print(unsigned int x, int count) { int i = 0; //控制,假如count为3, x 里边有三个 1 if( bit(x) == count ) { for(i=0; i<26; i++) { if( x & 1) { printf("%c ", (char)('a' + i)); } x = (x >> 1); } printf("\n"); } } int main() { const unsigned int N = 26; const unsigned int C = 3; const unsigned int X = (1 << N) - 1; //X=(1<<26)-1 unsigned int i = 0; for(i=0; i<X; i++) { print(i, C); } return 0; } 这个解法真是666!#=,=

优秀的个人博客,低调大师

java基础学习_集合类04_Map接口、Collections工具类_day18总结

========================================================================================================================================================== 涉及到的知识点有: 1:Map接口(掌握) (1)Map接口的概述 (2)Map接口和Collection接口的区别? (3)Map接口的功能概述 A:添加功能 B:删除功能 C:判断功能 D:获取功能 E:长度功能 (4)Map集合的遍历 A:键找值 B:键值对对象找键和值 (5)HashMap集合(唯一) A:HashMap集合的概述 B:HashMap集合的案例 C:LinkedHashMap集合的概述(唯一和有序) (6)TreeMap集合(排序和唯一) A:TreeMap类概述 B:TreeMap集合的案例 (7)Map集合案例 A:统计一个字符串中每个字符出现的次数(要对着思路会写) B:集合的嵌套遍历 (8)面试题 a:HashMap类和Hashtable类的区别 b:List、Set、Map等接口是否都继承自Map接口? 2:Collections工具类(理解) (1)Collections类的概述 (2)面试题:Collection和Collections的区别 (3)Collections工具类的常见成员方法 (4)Collections工具类的案例 A:ArrayList集合存储自定义对象的排序 B:模拟斗地主洗牌和发牌 C:模拟斗地主洗牌和发牌并对牌进行排序==========================================================================================================================================================1:Map接口(掌握) (1)Map接口的概述 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。 (2)Map接口和Collection接口的区别? A:Map集合存储的元素是键值对形式出现的,Map集合的键是唯一,值是可以重复的。可以把这个理解为:夫妻对。 B:Collection集合存储的元素是单独出现的,子接口Set元素唯一,子接口List元素可重复。可以把这个理解为:光棍(11.11)。 C:Map集合的数据结构只针对键有效,跟值无关。 D:Collection集合的数据结构针对元素有效。--------------------------------------- (3)Map接口的功能概述 A:添加功能 V put(K key, V value) 添加元素/替换元素 如果键是第一次存储,就直接存储元素,而返回的值是null。 如果键不是第一次存储,就用现在的值把以前的值替换掉,而返回的值是以前的值。 B:删除功能 void clear() 移除所有的键值对元素 V remove(Object key) 根据键删除键值对元素,并把值返回 C:判断功能 boolean containsKey(Object key) 判断集合是否包含指定的键 boolean containsValue(Object value) 判断集合是否包含指定的值 boolean isEmpty() 判断集合是否为空 D:获取功能 Set<Map.Entry<K, V>> entrySet() 返回的是键值对对象的集合 V get(Object key) 根据键获取值,返回的是值 Set<K> keySet() 获取集合中所有键的集合(因为键不可重复) Collection<V> values() 获取集合中所有值的集合(因为值可以重复) E:长度功能 int size() 返回集合中的键值对的对数 1 package cn.itcast_01; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /* 7 * 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取学生姓名,请问怎么做呢? 8 * 如果采用前面讲解过的集合,我们只能把学生学号和学生姓名作为一个对象的成员变量,然后存储整个对象,将来遍历的时候,判断,获取对应的名称。 9 * 但是呢,如果我都能把学生姓名拿出来了,我还需要根据编号去找吗? 10 * 11 * 针对我们目前的这种需求:仅仅知道学号,就想知道学生姓名的情况,Java就提供了一种新的集合 Map(接口)。 12 * 通过查看API,我们知道Map集合的一个最大的特点,就是它可以存储键值对的元素。这个时候存储我们上面的需求,就可以这样做: 13 * Set(不可重复) List(可重复) 14 * 键 映射 值 15 * 学号1 对应 姓名1 16 * 学号2 对应 姓名2 17 * 学号3 对应 姓名3 18 * 学号2(不行) 不能对应 姓名4 19 * 学号4 对应 姓名4 20 * 21 * Map集合的特点: 22 * 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。 23 * 24 * Map集合和Collection集合的区别? 25 * Map集合存储元素是成对出现的,Map集合的键是唯一的,值是可重复的。可以把这个理解为:夫妻对 26 * Collection集合存储元素是单独出现的,Collection的儿子Set是唯一的,List是可重复的。可以把这个理解为:光棍(11.11) 27 * 28 * 注意: 29 * Map集合的数据结构值针对键有效,跟值无关。 30 * HashMap,TreeMap等会讲。 31 * Collection集合的数据结构是针对元素有效。 32 * 33 * Map集合的功能概述: 34 * 1:添加功能 35 * V put(K key, V value) 添加元素/替换元素 36 * 如果键是第一次存储,就直接存储元素,而返回的值是null。 37 * 如果键不是第一次存储,就用现在的值把以前的值替换掉,而返回的值是以前的值。 38 * 2:删除功能 39 * void clear() 移除所有的键值对元素 40 * V remove(Object key) 根据键删除键值对元素,并把值返回 41 * 3:判断功能 42 * boolean containsKey(Object key) 判断集合是否包含指定的键 43 * boolean containsValue(Object value) 判断集合是否包含指定的值 44 * boolean isEmpty() 判断集合是否为空 45 * 4:获取功能 46 * Set<Map.Entry<K, V>> entrySet() 返回的是键值对对象的集合 47 * V get(Object key) 根据键获取值 48 * Set<K> keySet() 获取集合中所有键的集合 49 * Collection<V> values() 获取集合中所有值的集合 50 * 5:长度功能 51 * int size() 返回集合中的键值对的对数 52 */ 53 public class MapDemo { 54 public static void main(String[] args) { 55 // 创建集合对象,且键和值都是字符串类型 56 Map<String, String> map = new HashMap<String, String>(); 57 58 // 添加元素 59 // V put(K key, V value) 添加元素 60 // 如果键是第一次存储,就直接存储元素,而返回的值是null。 61 // 如果键不是第一次存储,就用现在的值把以前的值替换掉,而返回的值是以前的值。 62 // System.out.println("put:" + map.put("文章", "马伊俐")); 63 // System.out.println("put:" + map.put("文章", "姚笛")); 64 65 map.put("邓超", "孙俪"); 66 map.put("黄晓明", "杨颖"); 67 map.put("周杰伦", "蔡依林"); 68 map.put("刘恺威", "杨幂"); 69 70 // void clear() 移除所有的键值对元素 71 // map.clear(); 72 73 // V remove(Object key) 根据键删除键值对元素,并把值返回 74 // System.out.println("remove:" + map.remove("黄晓明")); // 返回的是杨颖 75 // System.out.println("remove:" + map.remove("黄晓波")); // 键不存在的时候返回null 76 77 // boolean containsKey(Object key) 判断集合是否包含指定的键 78 // System.out.println("containsKey:" + map.containsKey("黄晓明")); // 包含指定的键时返回true 79 // System.out.println("containsKey:" + map.containsKey("黄晓波")); // 不包含指定的键时返回false 80 81 // boolean isEmpty() 判断集合是否为空 82 // System.out.println("isEmpty:"+map.isEmpty()); 83 84 // int size() 返回集合中的键值对的对数 85 System.out.println("size:"+map.size()); // 4 86 87 // 输出集合名称 88 System.out.println("map:" + map); // 重写了toString()方法 89 } 90 } MapDemo.java 1 package cn.itcast_01; 2 3 import java.util.Collection; 4 import java.util.HashMap; 5 import java.util.Map; 6 import java.util.Set; 7 8 /* 9 * Map集合的功能概述: 10 * 4:获取功能 11 * V get(Object key) 根据键获取值,返回的是值 12 * Set<K> keySet() 获取集合中所有键的集合 13 * Collection<V> values() 获取集合中所有值的集合 14 */ 15 public class MapDemo2 { 16 public static void main(String[] args) { 17 // 创建集合对象 18 Map<String, String> map = new HashMap<String, String>(); 19 20 // 创建元素并添加元素 21 map.put("邓超", "孙俪"); 22 map.put("黄晓明", "杨颖"); 23 map.put("周杰伦", "蔡依林"); 24 map.put("刘恺威", "杨幂"); 25 26 // V get(Object key) 根据键获取值,返回的是值 27 System.out.println("get:" + map.get("周杰伦")); 28 System.out.println("get:" + map.get("周杰")); // 返回null 29 System.out.println("----------------------"); 30 31 // Set<K> keySet() 获取集合中所有键的集合 32 Set<String> set = map.keySet(); 33 for (String key : set) { 34 System.out.println(key); 35 } 36 System.out.println("----------------------"); 37 38 // Collection<V> values() 获取集合中所有值的集合 39 Collection<String> con = map.values(); 40 for (String value : con) { 41 System.out.println(value); 42 } 43 } 44 } MapDemo2.java --------------------------------------- (4)Map集合的遍历 A:键找值 a:获取所有键的集合 b:遍历键的集合,得到每一个键 c:根据键到集合中去找值 B:键值对对象找键和值 a:获取所有的键值对对象的集合 b:遍历键值对对象的集合,获取每一个键值对对象 c:根据键值对对象找键和值 代码体现: Map<String,String> hm = new HashMap<String, String>(); hm.put("it002", "hello"); hm.put("it003", "world"); hm.put("it001", "java"); // 方式1:键找值 Set<String> set = hm.keySet(); for (String key : set) { String value = hm.get(key); System.out.println(key + "---" + value); } // 方式2:键值对对象找键和值 Set<Map.Entry<String,String>> set2 = hm.entrySet(); for (Map.Entry<String,String> me : set2) { String key = me.getKey(); String value = me.getValue(); System.out.println(key + "---" + value); } --------------------------------------- (5)HashMap集合(唯一) A:HashMap集合的概述 是基于哈希表的Map接口实现类。键是哈希表结构,可以保证键的唯一性。依赖于hashCode()和equals()方法来保证唯一性的。 B:HashMap集合的案例(注意:蓝色字体为键) a:HashMap<String, String> 1 package cn.itcast_02; 2 3 import java.util.HashMap; 4 import java.util.Set; 5 6 /* 7 * HashMap:是基于哈希表的Map接口实现类。 8 * 哈希表的作用是用来保证键的唯一性的。 9 * 依赖于hashCode()和equals()方法来保证唯一性的。 10 * 11 * 而String类默认重写了hashCode()和equals()方法。 12 * 13 * HashMap<String, String> 14 * 键:String 15 * 值:String 16 */ 17 public class HashMapDemo { 18 public static void main(String[] args) { 19 // 创建集合对象 20 HashMap<String, String> hm = new HashMap<String, String>(); 21 22 // 创建元素并添加元素 23 // String key1 = "it001"; 24 // String value1 = "马云"; 25 // hm.put(key1, value1); 26 27 // 添加元素到集合 28 hm.put("it001", "马云"); 29 hm.put("it003", "马化腾"); 30 hm.put("it004", "乔布斯"); 31 hm.put("it005", "张朝阳"); 32 hm.put("it002", "裘伯君"); 33 hm.put("it001", "比尔盖茨"); // 键相同,则值覆盖。 34 35 // 遍历集合 36 Set<String> set = hm.keySet(); 37 for (String key : set) { 38 String value = hm.get(key); 39 System.out.println(key + "---" + value); 40 } 41 } 42 } HashMapDemo.java 程序运行的结果为:it004---乔布斯 it003---马化腾 it005---张朝阳 it002---裘伯君 it001---比尔盖茨 b:HashMap<Integer, String> 1 package cn.itcast_02; 2 3 import java.util.HashMap; 4 import java.util.Set; 5 6 /* 7 * HashMap<Integer, String> 8 * 键:Integer 9 * 值:String 10 * 11 * 而Integer类默认也重写了hashCode()和equals()方法。 12 * 13 */ 14 public class HashMapDemo2 { 15 public static void main(String[] args) { 16 // 创建集合对象 17 HashMap<Integer, String> hm = new HashMap<Integer, String>(); 18 19 // 创建元素并添加元素 20 // Integer i = new Integer(27); 21 // Integer i = 27; // 自动装箱 22 // String s = "林青霞"; 23 // hm.put(i, s); 24 25 // 添加元素到集合 26 hm.put(35, "风清扬"); 27 hm.put(29, "林青霞"); 28 hm.put(27, "林青霞"); 29 hm.put(28, "刘意"); 30 31 32 // 0开头的表示的是八进制数据,下面的写法是八进制的写法,但是不能出现8以上的单个数据 33 // hm.put(003, "hello"); 34 // hm.put(006, "hello"); 35 // hm.put(007, "hello"); 36 // hm.put(008, "hello"); // 错误 37 38 // 遍历集合 39 Set<Integer> set = hm.keySet(); 40 for (Integer key : set) { 41 String value = hm.get(key); 42 System.out.println(key + "---" + value); 43 } 44 45 // 下面这种方式仅仅是集合元素的字符串表示,不是遍历 46 // System.out.println("hm:" + hm); 47 } 48 } HashMapDemo2.java 程序运行的结果为:35---风清扬 27---林青霞 28---刘意 29---林青霞 c:HashMap<String, Student> 1 package cn.itcast_02; 2 3 public class Student { 4 private String name; 5 private int age; 6 7 public Student() { 8 super(); 9 } 10 11 public Student(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 } Student.java 1 package cn.itcast_02; 2 3 import java.util.HashMap; 4 import java.util.Set; 5 6 /* 7 * HashMap<String, Student> 8 * 键:String 学号 9 * 值:Student 学生对象 10 */ 11 public class HashMapDemo3 { 12 public static void main(String[] args) { 13 // 创建集合对象 14 HashMap<String, Student> hm = new HashMap<String, Student>(); 15 16 // 创建学生对象 17 Student s1 = new Student("周星驰", 58); 18 Student s2 = new Student("刘德华", 55); 19 Student s3 = new Student("梁朝伟", 54); 20 Student s4 = new Student("郭富城", 50); 21 Student s5 = new Student("周星驰", 58); // 此时的学生对象是值,键值对的值是不具备唯一性的。 22 23 // 添加元素到集合 24 hm.put("9527", s1); 25 hm.put("9522", s2); 26 hm.put("9524", s3); 27 hm.put("9529", s4); 28 hm.put("9521", s5); 29 30 // 遍历集合 31 Set<String> set = hm.keySet(); 32 for (String key : set) { 33 Student value = hm.get(key); 34 System.out.println(key + "---" + value.getName() + "---" + value.getAge()); 35 } 36 } 37 } HashMapDemo3.java 程序运行的结果为:9521---周星驰---58 9524---梁朝伟---54 9522---刘德华---55 9529---郭富城---50 9527---周星驰---58 d:HashMap<Student, String> 1 package cn.itcast_02; 2 3 public class Student { 4 private String name; 5 private int age; 6 7 public Student() { 8 super(); 9 } 10 11 public Student(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 33 @Override 34 public int hashCode() { 35 final int prime = 31; 36 int result = 1; 37 result = prime * result + age; 38 result = prime * result + ((name == null) ? 0 : name.hashCode()); 39 return result; 40 } 41 42 @Override 43 public boolean equals(Object obj) { 44 if (this == obj) 45 return true; 46 if (obj == null) 47 return false; 48 if (getClass() != obj.getClass()) 49 return false; 50 Student other = (Student) obj; 51 if (age != other.age) 52 return false; 53 if (name == null) { 54 if (other.name != null) 55 return false; 56 } else if (!name.equals(other.name)) 57 return false; 58 return true; 59 } 60 61 } Student.java 1 package cn.itcast_02; 2 3 import java.util.HashMap; 4 import java.util.Set; 5 6 /* 7 * HashMap<Student, String> 8 * 键:Student 9 * 要求:如果键的成员变量值都相同,则为同一个对象。即:键相同,则值覆盖。 10 * 即:要手动重写键Student类的hashCode()和equals()方法。 11 * 值:String 12 */ 13 public class HashMapDemo4 { 14 public static void main(String[] args) { 15 // 创建集合对象 16 HashMap<Student, String> hm = new HashMap<Student, String>(); 17 18 // 创建学生对象 19 Student s1 = new Student("貂蝉", 27); 20 Student s2 = new Student("王昭君", 30); 21 Student s3 = new Student("西施", 33); 22 Student s4 = new Student("杨玉环", 35); 23 Student s5 = new Student("貂蝉", 27); // 此时的学生对象是键,而键值对的键具备唯一性。即:键相同,则值覆盖。 24 25 // 添加元素到集合 26 hm.put(s1, "8888"); 27 hm.put(s2, "6666"); 28 hm.put(s3, "5555"); 29 hm.put(s4, "7777"); 30 hm.put(s5, "9999"); 31 32 // 遍历集合 33 Set<Student> set = hm.keySet(); 34 for (Student key : set) { 35 String value = hm.get(key); 36 System.out.println(key.getName() + "---" + key.getAge() + "---" + value); 37 } 38 } 39 } HashMapDemo4.java 程序运行的结果为:王昭君---30---6666 貂蝉---27---9999 杨玉环---35---7777 西施---33---5555 C:LinkedHashMap集合的概述(唯一和有序) 是Map接口的哈希表和链表的实现类,具有可预知的迭代顺序。 由哈希表保证键的唯一性。 由链表保证键盘的有序(存储和取出的顺序一致)。 1 package cn.itcast_03; 2 3 import java.util.LinkedHashMap; 4 import java.util.Set; 5 6 /* 7 * LinkedHashMap:是Map接口的哈希表和链接列表实现类,具有可预知的迭代顺序。 8 * 由哈希表保证键的唯一性。 9 * 由链表保证键盘的有序(存储和取出的顺序一致)。 10 */ 11 public class LinkedHashMapDemo { 12 public static void main(String[] args) { 13 // 创建集合对象 14 LinkedHashMap<String, String> hm = new LinkedHashMap<String, String>(); 15 16 // 创建并添加元素到集合 17 hm.put("2345", "hello"); 18 hm.put("1234", "world"); 19 hm.put("3456", "java"); 20 hm.put("1234", "javaee"); // 键相同,则值覆盖。 21 hm.put("3456", "android"); // 键相同,则值覆盖。 22 23 // 遍历结合 24 Set<String> set = hm.keySet(); 25 for (String key : set) { 26 String value = hm.get(key); 27 System.out.println(key + "---" + value); 28 } 29 } 30 } LinkedHashMapDemo.java 程序运行的结果为:2345---hello 1234---javaee 3456---android --------------------------------------- (6)TreeMap集合(排序和唯一) A:TreeMap类概述 是基于红黑树的Map接口的实现类。键是红黑树结构,可以保证键的排序和唯一性。 B:TreeMap集合的案例(注意:蓝色字体为键) a:TreeMap<String, String> 自然排序: String类默认实现了Comparable接口,重写了compareTo()方法,故而是自然排序。 1 package cn.itcast_04; 2 3 public class Student { 4 private String name; 5 private int age; 6 7 public Student() { 8 super(); 9 } 10 11 public Student(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 } Student.java 1 package cn.itcast_04; 2 3 import java.util.Set; 4 import java.util.TreeMap; 5 6 /* 7 * TreeMap:是基于红黑树的Map接口的实现类。 8 * 键是红黑树结构,可以保证键的排序和唯一性 9 * 10 * TreeMap<String, String> 11 * 键:String 12 * 值:String 13 * 14 * 自然排序: 15 * String类默认实现了Comparable接口,重写了compareTo()方法,故而是自然排序。 16 */ 17 public class TreeMapDemo { 18 public static void main(String[] args) { 19 // 创建集合对象 20 TreeMap<String, String> tm = new TreeMap<String, String>(); 21 22 // 创建元素并添加元素到集合 23 tm.put("hello", "你好"); 24 tm.put("world", "世界"); 25 tm.put("java", "爪哇"); 26 tm.put("world", "世界2"); // 键相同,则值覆盖。 27 tm.put("javaee", "爪哇EE"); 28 29 // 遍历集合 30 Set<String> set = tm.keySet(); 31 for (String key : set) { 32 String value = tm.get(key); 33 System.out.println(key + "---" + value); 34 } 35 } 36 } TreeMapDemo.java 程序运行的结果为:hello---你好 java---爪哇 javaee---爪哇EE world---世界2 b:TreeMap<Student, String> 比较器排序: 让集合的构造方法接收一个比较器接口 Comparator的实现类对象,一般用匿名内部类实现。 1 package cn.itcast_04; 2 3 public class Student { 4 private String name; 5 private int age; 6 7 public Student() { 8 super(); 9 } 10 11 public Student(String name, int age) { 12 super(); 13 this.name = name; 14 this.age = age; 15 } 16 17 public String getName() { 18 return name; 19 } 20 21 public void setName(String name) { 22 this.name = name; 23 } 24 25 public int getAge() { 26 return age; 27 } 28 29 public void setAge(int age) { 30 this.age = age; 31 } 32 } Student.java 1 package cn.itcast_04; 2 3 import java.util.Comparator; 4 import java.util.Set; 5 import java.util.TreeMap; 6 7 /* 8 * TreeMap<Student, String> 9 * 键:Student 10 * 值:String 11 * 12 * 比较器排序: 13 * 让集合的构造方法接收一个比较器接口 Comparator的实现类对象,一般用匿名内部类实现。 14 * 15 * 如果一个方法的参数是接口,那么真正需要的是接口的实现类的对象,而且该方法只调用一次。 16 * 所以使用匿名内部类就可以实现这个东西,这样就不用自己去重新写一个具体的实现类了。其实这种方式是很常见的。 17 */ 18 public class TreeMapDemo2 { 19 public static void main(String[] args) { 20 // 创建集合对象 21 TreeMap<Student, String> tm = new TreeMap<Student, String>( 22 new Comparator<Student>() { 23 @Override 24 public int compare(Student s1, Student s2) { 25 // 主要条件 26 int num = s1.getAge() - s2.getAge(); 27 // 次要条件 28 int num2 = (num == 0 ? s1.getName().compareTo(s2.getName()) : num); 29 return num2; 30 } 31 }); 32 33 // 创建学生对象 34 Student s1 = new Student("潘安", 30); 35 Student s2 = new Student("柳下惠", 35); 36 Student s3 = new Student("唐伯虎", 33); 37 Student s4 = new Student("燕青", 32); 38 Student s5 = new Student("唐伯虎", 33); // 键相同,则值覆盖。即最终唐伯虎是汉朝的。 39 40 // 添加元素到集合 41 tm.put(s1, "宋朝"); 42 tm.put(s2, "元朝"); 43 tm.put(s3, "明朝"); 44 tm.put(s4, "清朝"); 45 tm.put(s5, "汉朝"); 46 47 // 遍历集合 48 Set<Student> set = tm.keySet(); 49 for (Student key : set) { 50 String value = tm.get(key); 51 System.out.println(key.getName() + "---" + key.getAge() + "---" + value); 52 } 53 } 54 } TreeMapDemo2.java 程序运行的结果为:潘安---30---宋朝 燕青---32---清朝 唐伯虎---33---汉朝 柳下惠---35---元朝 --------------------------------------- (7)Map集合案例 A:统计一个字符串中每个字符出现的次数(要对着思路会写) 示例代码如下: 1 package cn.itcast_05; 2 3 import java.util.Scanner; 4 import java.util.Set; 5 import java.util.TreeMap; 6 7 /* 8 * 需求 :"aababcabcdabcde",获取字符串中每一个字母出现的次数。 9 * 要求输出结果的格式为 a(5)b(4)c(3)d(2)e(1) 10 * 11 * 分析: 12 * A:定义一个字符串(可以改进为键盘录入); 13 * B:定义一个TreeMap集合(为了使用其自带的排序功能); 14 * 键:Character 15 * 值:Integer 16 * Character类默认实现了Comparable接口,重写了compareTo()方法,故而是自然排序。 17 * C:把字符串转换为字符数组; 18 * D:遍历字符数组,得到每一个字符; 19 * E:拿得到的字符作为键到集合中去找值,看返回的值值: 20 * 如果是null:说明该键不存在,就把该字符作为键,把次数1作为值进行存储到集合中; 21 * 如果不是null:说明该键存在,就把值加1,然后重写存储该键和值到集合中。 22 * F:定义字符串缓冲区变量(对象); 23 * G:遍历集合,获取到每一个键和值,按照输出格式要求进行拼接; 24 * H:把字符串缓冲区内容转换为字符串输出。 25 * 26 * 测试: 27 * 录入:linqingxia 28 * 结果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1) 29 */ 30 public class TreeMapDemo { 31 public static void main(String[] args) { 32 // 定义一个字符串(可以改进为键盘录入) 33 Scanner sc = new Scanner(System.in); 34 System.out.println("请输入一个字符串:"); 35 String line = sc.nextLine(); 36 37 // 定义一个TreeMap集合 38 TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>(); 39 40 // 把字符串转换为字符数组 41 char[] chs = line.toCharArray(); 42 43 // 遍历字符数组,得到每一个字符 44 for(char ch : chs){ 45 // 拿刚才得到的字符作为键到集合中去找值,看返回值 46 Integer i = tm.get(ch); // 自动装箱 47 48 // 如果是null:说明该键不存在,就把该字符作为键,把次数1作为值进行存储到集合中 49 if(i == null){ 50 tm.put(ch, 1); 51 }else { 52 // 如果不是null:说明该键存在,就把值加1,然后重写存储该键和值到集合中 53 i++; // 自动拆箱,再自动装箱 54 tm.put(ch,i); 55 } 56 } 57 58 // 定义字符串缓冲区(对象) 59 StringBuilder sb= new StringBuilder(); 60 61 // 遍历集合,得到键和值,进行按照要求拼接 62 Set<Character> set = tm.keySet(); 63 for(Character key : set){ 64 Integer value = tm.get(key); // 得到键 65 sb.append(key).append("(").append(value).append(")"); // a(5)b(4)c(3)d(2)e(1) 66 } 67 68 // 把字符串缓冲区内容转换为字符串输出 69 String result = sb.toString(); 70 System.out.println("result:"+result); 71 } 72 } TreeMapDemo.java 程序运行的结果为: 请输入一个字符串: aababcabcdabcde result:a(5)b(4)c(3)d(2)e(1) B:集合的嵌套遍历(注意:蓝色字体为键) a:HashMap嵌套HashMap,即 HashMap<String, HashMap<String, Integer>> 1 package cn.itcast_05; 2 3 import java.util.HashMap; 4 import java.util.Set; 5 6 /* 7 * HashMap嵌套HashMap 8 * 9 * 存储的格式为: 10 * 传智播客 11 * 键 值 12 * jc---基础班 13 * 键 值 14 * 陈玉楼 ---20 15 * 高跃---22 16 * 17 * 键 值 18 * jy---就业班 19 * 键 值 20 * 李杰---21 21 * 曹石磊---23 22 * 输出形式为: 23 * jc 24 * 陈玉楼---20 25 * 高跃---22 26 * jy 27 * 李杰---21 28 * 曹石磊---23 29 * 30 * 先存储元素,然后遍历元素 31 */ 32 public class HashMapIncludeHashMapDemo { 33 public static void main(String[] args) { 34 // 创建传智播客集合对象 35 HashMap<String, HashMap<String, Integer>> czbkMap = new HashMap<String, HashMap<String, Integer>>(); 36 37 // 创建基础班集合对象 38 HashMap<String, Integer> jcMap = new HashMap<String, Integer>(); 39 // 添加元素到基础班集合 40 jcMap.put("陈玉楼", 20); 41 jcMap.put("高跃", 22); 42 // 把基础班添加到传智播客大集合 43 czbkMap.put("jc", jcMap); 44 45 // 创建就业班集合对象 46 HashMap<String, Integer> jyMap = new HashMap<String, Integer>(); 47 // 添加元素到就业班集合 48 jyMap.put("李杰", 21); 49 jyMap.put("曹石磊", 23); 50 // 把基础班添加到传智播客大集合 51 czbkMap.put("jy", jyMap); 52 53 // 遍历传智播客大集合 54 Set<String> czbkMapSet = czbkMap.keySet(); // 得到键 55 for(String czbkMapKey : czbkMapSet){ // 遍历键 56 System.out.println(czbkMapKey); // 输出键 57 HashMap<String, Integer> czbkMapValue = czbkMap.get(czbkMapKey); // 根据键获取值,返回的是值,该值是hashMap集合 58 // 遍历班级集合 59 Set<String> czbkMapValueSet = czbkMapValue.keySet(); // 得到键 60 for(String czbkMapValueKey : czbkMapValueSet){ // 遍历键 61 Integer czbkMapValueValue = czbkMapValue.get(czbkMapValueKey); // 根据键获取值,返回的是值 62 System.out.println("\t"+czbkMapValueKey+"---"+czbkMapValueValue); 63 } 64 } 65 } 66 } HashMapIncludeHashMapDemo.java 程序运行结果为:jc 高跃---22 陈玉楼---20 jy 曹石磊---23 李杰---21 b:HashMap嵌套ArrayList,即 HashMap<String, ArrayList<String>> 1 package cn.itcast_05; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.Set; 6 7 /* 8 * HashMap结合嵌套ArrayList集合并遍历。 9 * 10 * 需求: 11 * 假设HashMap集合的元素是ArrayList。每个HashMap集合有3个ArrayList集合元素。 12 * 每一个ArrayList集合的值是字符串。每个ArrayList集合有2个元素。 13 * 元素我已经完成,请遍历。 14 * 15 * 存储的格式为: 16 * 键 值 17 * 三国演义---ArrayList 18 * 吕布 19 * 周瑜 20 * 笑傲江湖---ArrayList 21 * 令狐冲 22 * 林平之 23 * 神雕侠侣---ArrayList 24 * 郭靖 25 * 杨过 26 * 27 * 输出形式为: 28 * 三国演义 29 * 吕布 30 * 周瑜 31 * 笑傲江湖 32 * 令狐冲 33 * 林平之 34 * 神雕侠侣 35 * 郭靖 36 * 杨过 37 */ 38 public class HashMapIncludeArrayListDemo { 39 public static void main(String[] args) { 40 // 创建HashMap集合对象 41 HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>(); 42 43 // 创建元素集合1 44 ArrayList<String> array1 = new ArrayList<String>(); 45 array1.add("吕布"); 46 array1.add("周瑜"); 47 // 把元素添加到hm里面 48 hm.put("三国演义", array1); 49 50 // 创建元素集合2 51 ArrayList<String> array2 = new ArrayList<String>(); 52 array2.add("令狐冲"); 53 array2.add("林平之"); 54 // 把元素添加到hm里面 55 hm.put("笑傲江湖", array2); 56 57 // 创建元素集合3 58 ArrayList<String> array3 = new ArrayList<String>(); 59 array3.add("郭靖"); 60 array3.add("杨过"); 61 // 把元素添加到hm里面 62 hm.put("神雕侠侣", array3); 63 64 // 遍历HashMap集合 65 Set<String> set = hm.keySet(); // 得到键 66 for(String key : set){ // 遍历键 67 System.out.println(key); // 输出键 68 ArrayList<String> value = hm.get(key); // 根据键获取值,返回的是值,该值是ArrayList集合 69 // 遍历ArrayList集合 70 for(String s : value){ 71 System.out.println("\t" + s); 72 } 73 } 74 } 75 } HashMapIncludeArrayListDemo.java 程序的运行结果为:神雕侠侣 郭靖 杨过 三国演义 吕布 周瑜 笑傲江湖 令狐冲 林平之 c:ArrayList嵌套HashMap,即 ArrayList<HashMap<String, String>> 1 package cn.itcast_05; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.Set; 6 7 /* 8 * ArrayList集合嵌套HashMap集合并遍历。 9 * 10 * 需求: 11 * 假设ArrayList集合的元素是HashMap。每个ArrayList集合有3个HashMap集合元素。 12 * 每一个HashMap集合的键和值都是字符串。每个HashMap集合有2个元素。 13 * 元素我已经完成,请遍历。 14 * 15 *输出形式为: 16 * ArrayList 17 * 键 值 18 * 周瑜---小乔 19 * 吕布---貂蝉 20 * 21 * 郭靖---黄蓉 22 * 杨过---小龙女 23 * 24 * 令狐冲---任盈盈 25 * 林平之---岳灵珊 26 */ 27 public class ArrayListIncludeHashMapDemo { 28 public static void main(String[] args) { 29 // 创建ArrayList集合对象 30 ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>(); 31 32 // 创建元素集合1 33 HashMap<String, String> hm1 = new HashMap<String, String>(); 34 hm1.put("周瑜", "小乔"); 35 hm1.put("吕布", "貂蝉"); 36 // 把元素添加到array里面 37 array.add(hm1); 38 39 // 创建元素集合2 40 HashMap<String, String> hm2 = new HashMap<String, String>(); 41 hm2.put("郭靖", "黄蓉"); 42 hm2.put("杨过", "小龙女"); 43 // 把元素添加到array里面 44 array.add(hm2); 45 46 // 创建元素集合3 47 HashMap<String, String> hm3 = new HashMap<String, String>(); 48 hm3.put("令狐冲", "任盈盈"); 49 hm3.put("林平之", "岳灵珊"); 50 // 把元素添加到array里面 51 array.add(hm3); 52 53 // 遍历ArrayList集合 54 for (HashMap<String, String> hm : array) { 55 // 遍历HashMap集合 56 Set<String> set = hm.keySet(); // 得到键 57 for (String key : set) { 58 String value = hm.get(key); // 根据键获取值,返回的是值 59 System.out.println(key + "---" + value); 60 } 61 System.out.println(); 62 } 63 } 64 } ArrayListIncludeHashMapDemo.java 程序运行结果为:吕布---貂蝉 周瑜---小乔 杨过---小龙女 郭靖---黄蓉 令狐冲---任盈盈 林平之---岳灵珊 d:HashMap嵌套HashMap嵌套ArrayList(多层嵌套),即 HashMap<String, HashMap<String, ArrayList<Student>>> 1 package cn.itcast_06; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.Set; 6 7 /* 8 * HashMap嵌套HashMap嵌套ArrayList(多层嵌套) 9 * 10 * 为了更符合要求: 11 * 这次的数据是学生对象。 12 * 13 * 存储的格式为: 14 * 传智播客 15 * 键 值 16 * bj---北京校区 17 * 键 值 18 * jc---基础班 19 * ArrayList集合 20 * 林青霞--- 27 21 * 风清扬---30 22 * jy---就业班 23 * 赵雅芝---28 24 * 武鑫---29 25 * sh---上海校区 26 * jc---基础班 27 * 郭美美---20 28 * 犀利哥---22 29 * jy---就业班 30 * 罗玉凤---21 31 * 马征---23 32 * gz---广州校区 33 * jc---基础班 34 * 王力宏---30 35 * 李静磊---32 36 * jy---就业班 37 * 郎朗---31 38 * 柳岩---33 39 * xa---西安校区 40 * jc---基础班 41 * 范冰冰---27 42 * 刘意---30 43 * jy---就业班 44 * 李冰冰---28 45 * 张志豪---29 46 * 输出形式为: 47 * bj 48 * jc 49 * 林青霞---27 50 * 风清扬---30 51 * jy 52 * 赵雅芝---28 53 * 武鑫---29 54 * xa 55 * jc 56 * 范冰冰---27 57 * 刘意---30 58 * jy 59 * 李冰冰---28 60 * 张志豪---29 61 */ 62 public class HashMapIncludeHashMapIncludeArrayListDemo { 63 public static void main(String[] args) { 64 // 创建传智播客大集合对象 65 HashMap<String, HashMap<String, ArrayList<Student>>> czbkMap = new HashMap<String, HashMap<String, ArrayList<Student>>>(); 66 67 // 创建北京校区集合对象 68 HashMap<String, ArrayList<Student>> bjCzbkMap = new HashMap<String, ArrayList<Student>>(); 69 70 // 创建基础班集合对象 71 ArrayList<Student> array1 = new ArrayList<Student>(); 72 // 创建学生对象 73 Student s1 = new Student("林青霞", 27); 74 Student s2 = new Student("风清扬", 30); 75 // 把学生对象添加进基础班集合 76 array1.add(s1); 77 array1.add(s2); 78 79 // 创建就业班集合对象 80 ArrayList<Student> array2 = new ArrayList<Student>(); 81 // 创建学生对象 82 Student s3 = new Student("赵雅芝", 28); 83 Student s4 = new Student("武鑫", 29); 84 // 把学生对象添加进就业班集合 85 array2.add(s3); 86 array2.add(s4); 87 88 // 把基础班添加到北京校区集合 89 bjCzbkMap.put("jc", array1); 90 // 把就业班添加到北京校区集合 91 bjCzbkMap.put("jy", array2); 92 // 把北京校区添加到传智播客大集合 93 czbkMap.put("bj", bjCzbkMap); 94 95 // 上海校区数据自己做 96 // 广州校区数据自己做 97 98 // 创建西安校区集合对象(同理) 99 HashMap<String, ArrayList<Student>> xaCzbkMap = new HashMap<String, ArrayList<Student>>(); 100 ArrayList<Student> array3 = new ArrayList<Student>(); 101 Student s5 = new Student("范冰冰", 27); 102 Student s6 = new Student("刘意", 30); 103 array3.add(s5); 104 array3.add(s6); 105 ArrayList<Student> array4 = new ArrayList<Student>(); 106 Student s7 = new Student("李冰冰", 28); 107 Student s8 = new Student("张志豪", 29); 108 array4.add(s7); 109 array4.add(s8); 110 xaCzbkMap.put("jc", array3); 111 xaCzbkMap.put("jy", array4); 112 czbkMap.put("xa", xaCzbkMap); 113 114 // 遍历传智播客大集合 115 Set<String> czbkMapSet = czbkMap.keySet(); // 得到键 116 for (String czbkMapKey : czbkMapSet) { // 遍历键 117 System.out.println(czbkMapKey); // 输出键 118 HashMap<String, ArrayList<Student>> czbkMapValue = czbkMap.get(czbkMapKey); // 根据键获取值,返回的是值,该值是hashMap集合 119 // 遍历北京校区集合 120 Set<String> czbkMapValueSet = czbkMapValue.keySet(); // 得到键 121 for (String czbkMapValueKey : czbkMapValueSet) { // 遍历键 122 System.out.println("\t" + czbkMapValueKey); // 输出键 123 ArrayList<Student> czbkMapValueValue = czbkMapValue.get(czbkMapValueKey); // 根据键获取值,返回的是值,该值是ArrayList集合 124 // 遍历ArrayList集合 125 for (Student s : czbkMapValueValue) { 126 System.out.println("\t\t" + s.getName() + "---" + s.getAge()); 127 } 128 } 129 } 130 } 131 } HashMapIncludeHashMapIncludeArrayListDemo.java 程序运行结果为:bj jc 林青霞---27 风清扬---30 jy 赵雅芝---28 武鑫---29 xa jc 范冰冰---27 刘意---30 jy 李冰冰---28 张志豪---29 --------------------------------------- (8)面试题 a:HashMap类和Hashtable类的区别(注意:Hashtable的第二个单词是小写,继承了老版本jdk1.0的命名错误,如同System类下的静态方法Arraycopy()一样) HashMap类:不同步,线程不安全,效率高。允许null键和null值。 Hashtable类:同步,线程安全,效率低。不允许null键和null值。 其实HashMap类就是用来替代Hashtable类的。如同ArrayList类用来替代Vector类一样。 b:List、Set、Map等接口是否都继承自Map接口? List、Set不是继承自Map接口,它们继承自Collection接口。 Map接口本身就是一个顶层接口。 1 package cn.itcast_07; 2 3 import java.util.Hashtable; 4 5 /* 6 * 1:HashMap类和Hashtable类的区别? 7 * HashMap类:不同步,线程不安全,效率高。允许null键和null值。 8 * Hashtable类:同步,线程安全,效率低。不允许null键和null值。 9 * 其实HashMap类就是用来替代Hashtable类的。如同ArrayList类用来替代Vector类一样。 10 * 11 * 2:List、Set、Map等接口是否都继承自Map接口? 12 * List、Set不是继承自Map接口,它们继承自Collection接口。 13 * Map接口本身就是一个顶层接口。 14 */ 15 public class HashtableDemo { 16 public static void main(String[] args) { 17 // HashMap<String, String> hm = new HashMap<String, String>(); 18 // hm.put("it001", "hello"); 19 // hm.put(null, "world"); 20 // hm.put("java", null); 21 22 23 Hashtable<String, String> hm = new Hashtable<String, String>(); 24 hm.put("it001", "hello"); 25 hm.put(null, "world"); // NullPointerException 空指针异常 26 hm.put("java", null); // NullPointerException 空指针异常 27 28 System.out.println(hm); 29 } 30 } ----------------------------------------------------------------------------- 2:Collections工具类(理解) (1)Collections类的概述 是针对集合进行操作的工具类,都是静态方法。在java.util包下,父类是Object。 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。 (2)面试题:Collection和Collections的区别 a:Collection接口:是单列集合的顶层接口,有两个子接口List和Set。(Map是双列集合的顶层接口) b:Collections工具类:是针对集合进行操作的工具类,有对集合进行排序和二分查找的方法等。 (3)Collections工具类的常见成员方法 A:public static <T> void sort(List<T> list) 排序(默认情况下是自然顺序) B:public static <T> int binarySearch(List<?> list,T key) 二分查找(前提集合有序),若找到,则返回的是索引值;若找不到,则返回的是 -(元素个数+1) C:public static <T> T max(Collection<?> coll) 最大值 D:public static void reverse(List<?> list) 反转 E:public static void shuffle(List<?> list) 随机置换 1 package cn.itcast_01; 2 3 import java.util.Collections; 4 import java.util.List; 5 import java.util.ArrayList; 6 7 /* 8 * Collections:是针对集合进行操作的工具类,都是静态方法。 9 * 是针对集合进行操作的工具类,都是静态方法。在java.util包下,父类是Object。 10 * 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。 11 * 12 * 面试题: 13 * Collection和Collections的区别? 14 * Collection接口:是单列集合的顶层接口,有子接口List和Set。(Map是双列集合的顶层接口) 15 * Collections工具类:是针对集合操作的工具类,有对集合进行排序和二分查找的方法等。 16 * 17 * Collections类的常见成员方法: 18 * public static <T> void sort(List<T> list) 排序(默认情况下是自然顺序) 19 * public static <T> int binarySearch(List<?> list,T key) 二分查找(前提集合有序),若找到,则返回的是索引值;若找不到,则返回的是 -(元素个数+1) 20 * public static <T> T max(Collection<?> coll) 最大值 21 * public static void reverse(List<?> list) 反转 22 * public static void shuffle(List<?> list) 随机置换 23 * 24 * Integer类和String类都默认实现了Comparable接口,重写了compareTo()方法,故而是自然排序。 25 * 但是自定义对象默认没有实现Comparable接口。 26 */ 27 public class CollectionsDemo { 28 public static void main(String[] args) { 29 // 创建集合对象,List接口是集合,以List进行举例 30 List<Integer> list = new ArrayList<Integer>(); 31 32 // 添加元素 33 list.add(30); // 自动装箱 34 list.add(20); 35 list.add(50); 36 list.add(10); 37 list.add(40); 38 39 System.out.println("list:" + list); // list:[30, 20, 50, 10, 40] 40 41 // public static <T> void sort(List<T> list) 排序(默认情况下是自然顺序) 42 // Collections.sort(list); 43 // System.out.println("list:" + list); // list:[10, 20, 30, 40, 50] 44 45 // public static <T> int binarySearch(List<?> list,T key) 二分查找(前提集合有序),若找到,则返回的是索引值;若找不到,则返回的是 -(元素个数+1) 46 // System.out.println("binarySearch:" + Collections.binarySearch(list, 30)); // binarySearch:2 47 // System.out.println("binarySearch:" + Collections.binarySearch(list, 300));// binarySearch:-6 48 49 // public static <T> T max(Collection<?> coll) 最大值 50 // System.out.println("max:" + Collections.max(list)); // max:50 51 52 // public static void reverse(List<?> list) 反转 53 // Collections.reverse(list); // list:[40, 10, 50, 20, 30] 54 // System.out.println("list:" + list); 55 56 // public static void shuffle(List<?> list) 随机置换 57 Collections.shuffle(list); 58 System.out.println("list:" + list); 59 } 60 } CollectionsDemo.java (4)Collections工具类的案例 A:ArrayList集合存储自定义对象的排序 Collections可以针对ArrayList存储基本包装类的元素可以排序,存储自定义对象可不可以排序呢? 因为Integer类和String类都默认实现了Comparable接口,重写了compareTo()方法,故而自然排序。 但是自定义对象默认没有实现Comparable接口,所以不能进行自然排序。 示例代码如下:(注意:示例代码中既有自然排序也有比较器排序) 1 package cn.itcast_02; 2 3 /** 4 * @author Administrator 5 * 6 */ 7 public class Student implements Comparable<Student> { 8 private String name; 9 private int age; 10 11 public Student() { 12 super(); 13 } 14 15 public Student(String name, int age) { 16 super(); 17 this.name = name; 18 this.age = age; 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 public void setName(String name) { 26 this.name = name; 27 } 28 29 public int getAge() { 30 return age; 31 } 32 33 public void setAge(int age) { 34 this.age = age; 35 } 36 37 @Override 38 public int compareTo(Student s) { 39 int num = this.age - s.age; // 从上到下,从小到大,顺序,升序 40 int num2 = (num == 0 ? this.name.compareTo(s.name) : num); 41 return num2; 42 } 43 44 } 1 package cn.itcast_02; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Comparator; 6 import java.util.List; 7 8 /* 9 * Collections可以针对ArrayList存储基本包装类的元素排序,存储自定义对象可不可以排序呢? 10 */ 11 public class CollectionsDemo { 12 public static void main(String[] args) { 13 // 创建集合对象,List接口是集合,以List进行举例 14 List<Student> list = new ArrayList<Student>(); 15 16 // 创建学生对象 17 Student s1 = new Student("林青霞", 27); 18 Student s2 = new Student("风清扬", 30); 19 Student s3 = new Student("刘晓曲", 28); 20 Student s4 = new Student("武鑫", 29); 21 Student s5 = new Student("林青霞", 27); 22 23 // 添加元素对象到集合 24 list.add(s1); 25 list.add(s2); 26 list.add(s3); 27 list.add(s4); 28 list.add(s5); 29 30 // 调用Collections工具类中的方法使得ArrayList集合进行排序 31 // 方式一:自然排序 32 // Collections.sort(list); // 从上到下,从小到大,顺序,升序 33 // 如果学生类中的元素要想能够进行自然排序,学生类就必须实现自然排序接口,然后在学生类中重写compareTo()方法。否则编译就通不过。 34 35 // 如何去除ArrayList集合中的重复元素呢? 36 // 步骤一:我们需要重写自定义对象学生类中的equals()方法,自动生成即可。 37 // 步骤二:创建新集合; 38 // 步骤三:遍历旧集合,获取得到每一个元素;拿这个元素到新集合去找,看有没有,新集合中没有该元素就添加,有就不搭理它; 39 // 步骤四:遍历新集合。 40 // 综上:我们可以写一个去除ArrayList集合中的重复元素的功能。 41 42 // 这样我们通过Collectins工具类中的排序方法和去除ArrayList集合中的重复元素的功能, 43 // 就能实现ArrayList集合的排序和去重复元素了!!! 44 // 这个时候我还要Set集合、Map结合干嘛呢!!! 45 // 因为我的ArrayList集合就能干所有的事情了!!! 46 47 // 方式二:比较器排序,一般用匿名内部类实现,在匿名内部类中重写compare()方法。 48 // 如果同时有自然排序和比较器排序,则以比较器排序为主。 49 Collections.sort(list, new Comparator<Student>() { 50 // @Override 51 // public int compare(Student s1, Student s2) { 52 // return 0; 53 // } 54 55 @Override 56 public int compare(Student s1, Student s2) { 57 int num = s2.getAge() - s1.getAge(); // 从上到下,从大到小,倒序,降序 58 int num2 = (num == 0 ? s1.getName().compareTo(s2.getName()) : num); 59 return num2; 60 } 61 }); 62 63 // 遍历集合 64 for (Student s : list) { 65 System.out.println(s.getName() + "---" + s.getAge()); 66 } 67 } 68 } B:模拟斗地主洗牌和发牌 1 package cn.itcast_03; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 6 /* 7 * 模拟斗地主洗牌和发牌 8 * 9 * 分析: 10 * A:创建一个牌盒(集合) 11 * B:装牌 12 * C:洗牌 13 * D:发牌 14 * E:看牌 15 */ 16 public class PokerDemo { 17 public static void main(String[] args) { 18 // 创建一个牌盒(集合) 19 ArrayList<String> array = new ArrayList<String>(); 20 21 // 装牌 22 // 牌的組成: 23 // 黑桃A,黑桃2,黑桃3,...,黑桃K 24 // 红桃A,... 25 // 梅花A,... 26 // 方块A,... 27 // 定义一个花色字符串数组 28 String[] colors = { "", "", "", "" }; 29 // 定义一个点数字符串数组 30 String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" }; 31 // 装牌 32 // 增强for遍历花色(外循环) 4组X每组13个 A 2 3 ... Q K A 2 3 ... Q K A 2 3 ... Q K A 2 3 ... Q K 33 for (String color : colors) { 34 // 增强for遍历色数字(内循环) 35 for (String number : numbers) { 36 array.add(color.concat(number)); 37 } 38 } 39 array.add("小王"); 40 array.add("大王"); 41 42 System.out.println("array:" + array); // array:[A, 2, ... Q, K, A, 2, ... Q, K, A, 2, ... Q, K, A, 2, ... Q, K, 小王, 大王] 43 44 // 洗牌 45 Collections.shuffle(array); 46 47 System.out.println("array:" + array); 48 49 // 发牌 50 ArrayList<String> fengQingYang = new ArrayList<String>(); 51 ArrayList<String> linQingXia = new ArrayList<String>(); 52 ArrayList<String> liuYi = new ArrayList<String>(); 53 ArrayList<String> diPai = new ArrayList<String>(); 54 55 // int size() 元素的个数(即集合的长度) array.size() 集合的长度为54 56 for (int x = 0; x < array.size(); x++) { 57 if (x >= array.size() - 3) { // 51 >= 54 - 3 = 51 58 diPai.add(array.get(x)); // array.get(x) x是索引,当x = 51时,表示的是第52张牌 59 } else if (x % 3 == 0) { 60 fengQingYang.add(array.get(x)); 61 } else if (x % 3 == 1) { 62 linQingXia.add(array.get(x)); 63 } else if (x % 3 == 2) { 64 liuYi.add(array.get(x)); 65 } 66 } 67 68 // 看牌 69 lookPoker("风清扬", fengQingYang); 70 lookPoker("林青霞", linQingXia); 71 lookPoker("刘意", liuYi); 72 lookPoker("底牌", diPai); 73 } 74 75 public static void lookPoker(String name, ArrayList<String> array) { 76 System.out.print(name + "的牌是:"); 77 for (String s : array) { 78 System.out.print(s + " "); 79 } 80 System.out.println(); 81 } 82 } PokerDemo.java C:模拟斗地主洗牌和发牌并对牌进行排序 1 package cn.itcast_04; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.HashMap; 6 import java.util.TreeSet; 7 8 /* 9 * 模拟斗地主洗牌和发牌并对牌进行排序 10 * 11 * 思路: 12 * A:创建一个HashMap集合(键值对:存储制定的规则) 13 * B:创建一个ArrayList集合(创建一个牌盒) 14 * C:创建点数字符串数组和花字符串色数组 15 * D:从0开始往HashMap里面存储编号(键),并存储对应的牌(值),同时往ArrayList里面存储编号即可。 16 * E:洗牌(洗的是编号) 17 * F:发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收,因为TreeSet集合保证元素排序和唯一性) 18 * G:看牌(遍历TreeSet集合,获取编号后,到HashMap集合找对应的牌) 19 */ 20 public class PokerDemo { 21 public static void main(String[] args) { 22 // 创建一个HashMap集合(键值对:存储制定的规则) 23 HashMap<Integer, String> hm = new HashMap<Integer, String>(); 24 25 // 创建一个ArrayList集合(创建一个牌盒) 26 ArrayList<Integer> array = new ArrayList<Integer>(); 27 28 // 创建点数字符串数组和花色字符串数组 29 // 定义一个点数字符串数组 30 String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2", }; 31 // 定义一个花色字符串数组 32 String[] colors = { "", "", "", "" }; 33 34 // 从0开始往HashMap里面存储编号(键),并存储对应的牌(值),同时往ArrayList里面存储编号即可。 35 int index = 0; 36 // 增强for遍历色数字(外循环) 13组X每组4个 3 3 3 3 4 4 4 4 ...... A A A A 2 2 2 2 37 for (String number : numbers) { 38 // 增强for遍历花色(内循环) 39 for (String color : colors) { 40 String poker = color.concat(number); 41 hm.put(index, poker); 42 array.add(index); 43 index++; 44 } 45 } 46 hm.put(index, "小王"); 47 array.add(index); 48 index++; 49 hm.put(index, "大王"); 50 array.add(index); 51 52 // 洗牌(洗的是编号) 53 Collections.shuffle(array); 54 55 // 发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收,因为TreeSet集合保证元素排序和唯一性) 56 TreeSet<Integer> fengQingYang = new TreeSet<Integer>(); 57 TreeSet<Integer> linQingXia = new TreeSet<Integer>(); 58 TreeSet<Integer> liuYi = new TreeSet<Integer>(); 59 TreeSet<Integer> diPai = new TreeSet<Integer>(); 60 61 // int size() 元素的个数(即集合的长度) array.size() 集合的长度为54 62 for (int x = 0; x < array.size(); x++) { 63 if (x >= array.size() - 3) { // 51 >= 54 - 3 = 51 64 diPai.add(array.get(x)); // array.get(x) x是索引,当x = 51时,表示的是第52张牌 65 } else if (x % 3 == 0) { 66 fengQingYang.add(array.get(x)); 67 } else if (x % 3 == 1) { 68 linQingXia.add(array.get(x)); 69 } else if (x % 3 == 2) { 70 liuYi.add(array.get(x)); 71 } 72 } 73 74 // 看牌(遍历TreeSet集合,获取编号后,到HashMap集合找对应的牌) 75 lookPoker("风清扬", fengQingYang, hm); 76 lookPoker("林青霞", linQingXia, hm); 77 lookPoker("刘意", liuYi, hm); 78 lookPoker("底牌", diPai, hm); 79 } 80 81 // 写看牌的功能 82 public static void lookPoker(String name, TreeSet<Integer> ts, HashMap<Integer, String> hm) { 83 System.out.print(name + "的牌是:"); 84 for (Integer key : ts) { // 遍历键 85 String value = hm.get(key); // 根据键,获取对应的值 86 System.out.print(value + " "); 87 } 88 System.out.println(); 89 } 90 } PokerDemo.java =============================================================================我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

java编译器认为该程序存在安全隐患(没有学习泛型前)

注意:StudentDemo.java使用了未经检查或不安全的操作。 注意:要了解详细信息,请使用 -Xlint:unchecked重新编译。 java编译器认为该程序存在安全隐患 温馨提示:这不是编译失败,所以先不用理会,等学了泛型你就知道了。 如下图所示: 我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Oracle学习1--阿里云ECS上部署单实例数据库11.2.0.4

阿里云ECS安装Oracle11.2.0.4单实例数据库软件一、 环境准备阿里云ECS: 2C 8G 系统类型:centos7.4 Oracle包: 11.2.0.4 二、 云盘挂载这里使用了文件系统:先把云磁盘挂载到 ECS上使用,在 ECS上执行 fdisk -l 检查确认挂载磁盘使用 fdisk 对没有使用的磁盘进行分区,fdisk /dev/vdb ,(图为磁盘为整个分区)按照提示:选择 n,创建一个新的分区,选择作为主分区,分区号 1,开始位置 1,结束位置为最大值,即用整个磁盘作为分区。然后 w 保存退出。格式化成 ext4 分区,执行 mkfs -t ext4 /dev/vdb1修改/etc/fstab,在文件最后加上新加两个分区的定义,保存退出。挂载磁盘,执行mount /dev/vdb1 /orada

优秀的个人博客,低调大师

java基础学习_常用类02_Scanner类和String类_day12总结

==========================================================================================================================================================涉及到的知识点有: 1:Scanner类的概述和使用(了解) (1)Scanner类的概述 (2)Scanner类的构造方法 (3)Scanner类的成员方法 2:String类的概述和使用(掌握) (1)String类的概述 (2)String类的构造方法 (3)字符串的特点 (4)字符串的面试题(看程序写结果) (5)字符串的功能 (6)字符串的案例==========================================================================================================================================================1:Scanner类的概述和使用(了解) (1)Scanner类的概述 在JDK5以后出现的用于键盘录入数据的类。 是一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。 --------------------------------------- (2)Scanner类的构造方法 A:讲解了System.in这个东西。 它其实是标准的输入流,对应于键盘录入 B:构造方法 InputStream is = System.in; public Scanner(InputStream is) C:常用的格式 Scanner sc = new Scanner(System.in);--------------------------------------- (3)Scanner类的成员方法 1.基本方法的格式: A:public boolean hasNextXxx() 即判断下一个输入项是否是某种类型的。 其中Xxx可以是Int,Double等。如果需要判断是否包含下一个字符串,则可以省略Xxx。 B:public Xxx nextXxx() 获取某种类型的元素,即返回某种类型的元素。 Xxx的含义和上个方法中的Xxx相同。--------------------------------------- 2.要掌握的两个常用方法: A:public int nextInt() 获取一个int类型的值 B:public String nextLine() 获取一个String类型的值--------------------------------------- 3.需要注意的小问题: 对于同一个扫描器对象,若先获取一个数值,再获取一个字符串,会出现问题。 即:先nextInt()然后nextLine()的问题。 主要原因:就是那个换行符号的问题。 如何解决呢? A:先用键盘录入对象获取一个数值后,再创建一个新的键盘录入对象用来获取字符串。 B:把所有的数据都先按照字符串获取,然后要什么,你就对应的转换成什么。----------------------------------------------------------------------------- 2:String类的概述和使用(掌握) (1)String类的概述 字符串是由多个字符组成的一串数据(字符序列)。 字符串可以看成是字符数组,即它可以和字符数组进行相互转换。 在实际开发中,字符串的操作是最常见的操作,没有之一。 而Java没有内置的字符串类型,所以,就在Java类库中提供了一个类String 供我们来使用。--------------------------------------- (2)String类的构造方法 A:public String() 无参构造,即创建一个空内容的字符串对象。 B:public String(byte[] bytes) 把字节数组转成字符串,即使用一个字节数组构建一个字符串对象。 C:public String(char[] value) 把字符数组转成字符串,即使用一个字符数组构建一个字符串对象。 D:public String(byte[] bytes, int offset, int length) 把字节数组的一部分转成字符串,即使用一个字节数组构建一个字符串对象,指定开始的索引值,与使用的字节个数。 E:public String(char[] value, int offset, int count) 把字符数组的一部分转成字符串,即使用一个字符数组构建一个字符串对象,指定开始的索引值,与使用的字符个数。 F:public String(String original) 把字符串常量值转成一个字符串对象。 String s = new String("hello"); 这种构造方法会创建两个或一个对象。 G:String s = "hello"; 虽然不是构造方法,但是结果也是一个字符串对象。这种直接赋值的方法会创建一个或零个对象。 String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。--------------------------------------- (3)字符串的特点 A:字符串是常量,字符串的内容一旦被赋值,就不能被改变。 注意:这里指的是字符串的内容不能改变,而不是引用不能改变,引用可以改变。 即:字符串的内容会在字符串常量池里。每一个字符串的内容会有一个地址值。 B:字面值作为字符串对象和通过构造方法创建对象的不同? String s1 = new String("hello"); String s2 = "hello"; System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true ==(等号的比较的是): 基本类型:比较的就是值是否相同。 引用类型:比较的就是地址值是否相同。 equals(该方法比较的是): 只能是引用类型:默认情况下,比较的是地址值。 不过,我们可以根据情况自己重写该方法。一般重写都是自动生成,比较的是对象的成员变量值是否相同。 equals: 比较引用类型默认也是比较地址值是否相同,而String类重写了equals()方法,比较的是内容是否相同。内存如下图所示01/02: --------------------------------------- (4)字符串的面试题(看程序写结果) A:==和equals() String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true String s3 = new String("hello"); String s4 = "hello"; System.out.println(s3 == s4); // false System.out.println(s3.equals(s4)); // true String s5 = "hello"; String s6 = "hello"; System.out.println(s5 == s6); // true System.out.println(s5.equals(s6)); // true B:字符串的拼接 String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; System.out.println(s3 == s1 + s2); // false 字符串为变量时 System.out.println(s3.equals((s1 + s2))); // true System.out.println(s3 == "hello" + "world"); // true 字符串为常量时 System.out.println(s3.equals("hello" + "world")); // true 注意: 字符串如果是变量相加,先开空间,再拼接。 字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否则,就创建。--------------------------------------- (5)字符串的功能 A:String类的判断功能 public boolean equals(Object obj) 比较字符串的内容是否相同,区分大小写 public boolean equalsIgnoreCase(String str) 比较字符串的内容是否相同,忽略大小写 public boolean contains(String str) 判断大字符串中是否包含小字符串 public boolean startsWith(String str) 判断字符串是否以某个指定的字符串开头 public boolean endsWith(String str) 判断字符串是否以某个指定的字符串结尾 public boolean isEmpty() 判断字符串是否为空 注意: String s = ""; //字符串内容为空。 String s = null; //字符串对象为空。对象都不存在,所以不能调用方法,如果去调用方法,会出现空指针异常。--------------------------------------- B:String类的获取功能 public int length() 获取字符串的长度(字符个数)。 public char charAt(int index) 获取指定索引位置的字符。 public int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。 注意:形参为什么这里是int类型,而不是char类型? 原因是:'a'和97其实都可以代表'a'。形参为int类型时写'a'和97都可以,而为char类型时则只能写'a'了。 public int indexOf(String str) 返回指定字符串在此字符串中第一次出现处的索引。 public int indexOf(int ch, int fromIndex) 返回指定字符在此字符串中从指定位置后第一次出现处的索引。 public int indexOf(String str, int fromIndex) 返回指定字符串在此字符串中从指定位置后第一次出现处的索引。 public String substring(int start) 从指定位置开始截取字符串,默认到末尾(包含start这个索引)。 public String substring(int start, int end) 从指定位置开始到指定位置结束截取字符串(包括start索引但是不包end索引)。--------------------------------------- C:String类的转换功能 public byte[] getBytes() 把字符串转换为字节数组。 public char[] toCharArray() 把字符串转换为字符数组。 public static String valueOf(char[] chs) 把字符数组转成字符串。(方法重载) public static String valueOf(int i) 把int类型的数据转成字符串。(方法重载) 注意:String类的valueOf方法可以把任意类型的数据转成字符串。 public String toLowerCase() 把字符串转成小写。(注意:原串不变,生成的新串变为小写的) public String toUpperCase() 把字符串转成大写。(注意:原串不变,生成的新串变为小写的) public String concat(String str) 把字符串进行拼接。--------------------------------------- D:String类的其他功能 a:替换功能 public String replace(char old, char new) public String replace(String old, String new) b:去除字符串两端空格功能 public String trim() c:按字典顺序比较两个字符串功能 public int compareTo(String str) public int compareToIgnoreCase(String str) 示例: String s1 = "hello"; String s2 = "hello"; String s3 = "abc"; String s4 = "xyz"; System.out.println(s1.compareTo(s2)); // 0 System.out.println(s1.compareTo(s3)); // 7 System.out.println(s1.compareTo(s4)); // -16 比较不一样的时候,就用前一个串的第一个字符的ASCII减去后一个串的第一个字符的ASCII,得到一个int值返回。 若第一个字符相同,则比较第二个字符,以此类推。若都相同,则返回int值0。 若如下这样,查看该方法源码可知,返回的是第一个串比第二个串多的字符个数。 String s5 = "hello"; String s6 = "hel"; System.out.println(s5.compareTo(s6)); // -2--------------------------------------- (6)字符串的案例 A:模拟用户登录 B:字符串的遍历 C:统计字符串中大写、小写及数字字符的个数 D:把字符串的首字母转成大写,其他转成小写 E:把int数组拼接成一个指定格式的字符串输出 F:字符串反转 G:统计大串中小串出现的次数=============================================================================我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Python-OpenCV学习(七)边界框、最小矩形区域和最小闭圆的轮廓:

边界框、最小矩形区域和最小闭圆的轮廓:找到一个正方形轮廓很简单 找不规则的、歪斜的以及旋转的形状可用OpencV的cv2.findContours函数。 import cv2 import numpy as np img = cv2.pyrDown(cv2.imread("hammer.jpg", cv2.IMREAD_UNCHANGED)) ret, thresh = cv2.threshold(cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) , 127, 255, cv2.THRESH_BINARY) image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # find bounding box coordinates x,y,w,h = cv2.boundingRect(c) cv2.rectangle(img, (x,y), (x+w, y+h), (0, 255, 0), 2) # find minimum area rect = cv2.minAreaRect(c) # calculate coordinates of the minimum area rectangle box = cv2.boxPoints(rect) # normalize coordinates to integers box = np.int0(box) # draw contours cv2.drawContours(img, [box], 0, (0,0, 255), 3) # calculate center and radius of minimum enclosing circle (x,y),radius = cv2.minEnclosingCircle(c) # cast to integers center = (int(x),int(y)) radius = int(radius) # draw the circle img = cv2.circle(img,center,radius,(0,255,0),2) cv2.drawContours(img, contours, -1, (255, 0, 0), 1) cv2.imshow("contours", img) cv2.waitKey() cv2.destroyAllWindows() 结果:加载图片后先进行阈值处理,由于原图为黑白图片所以阈值较为简单计算简单的边界框: x,y,w,h=cv2.boundingRect(c) 转化为框的坐标及宽度,再画出框: cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) 第二步计算出包围最小的矩形区域 rect = cv2.minAreaRect(c) # calculate coordinates of the minimum area rectangle box = cv2.boxPoints(rect) # normalize coordinates to integers box = np.int0(box) 注意计算所得的顶点坐标为浮点型的,像素坐标必须为整数,所以必须做一个转换,然后画出这个矩形,可以用cv2.drawContours函数来: cv2.drawContours(img,[box],0,(0,0,255),3) 该函数的第二个参数接收一个保存着轮廓的数组,从而可以在一次操作中绘制一系列轮廓。第三个参数为所要绘制的轮廓的索引,-1为绘制所有的轮廓,否则只会绘制轮廓组中指定的轮廓最后检查的边界轮廓为最小闭圆: (x,y),radius = cv2.minEnclosingCircle(c) # cast to integers center = (int(x),int(y)) radius = int(radius) cv2.minEnclosingCircle函数会返回一个二元组,第一个元素为圆心坐标组成的元组,第二个元素为圆的半径值。

优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(一)——vector

STL是Standard Template Library的简称,中文名标准模板库。 从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。STL现在是C++的一部分,因此不用安装额外的库文件。 在C++标准中,STL被组织为下面的17个头文件: <algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>。 一、vector 1. vector的自我介绍 vector是向量的意思,可以理解为“可变长度的数组”。 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。 相当于一个动态数组,在你不知道需要的数组有多大时可以使用它来节省很多空间。在ACM中常常会出现内存溢出(out of memory)的问题导致WA(wrong answer),而使用vector就能节省很多内存。 使用vector要在程序开头加上#include<vector>来包含需要的头文件,还有加上“using namespace std;”,这样就可以在代码中使用vector了。 2.vector的定义 定义一个vector: vector<typename> vectorname; 这个定义相当于定义了一个一维的数组vectorname[SIZE],只不过这个SIZE的长度是可以改变的,随着你“加入”进去数的个数而改变。所谓“可变长度的数组”。 和一维的数组一样,这里的typename可以是任何的类型,如int,double,char,string,long long ,也可以是结构体,甚至是STL的容器如vector,set,queue,stack等。注意!如果typename也是一个容器的话,比如vector<vector<int> > vectorname,要在两个'<'符号之间加上一个空格,否则编译时会误以为是位移操作。 3.vector的创建 vector<double> vec1; // 创建一个空的double向量 vector<int> vec(66); // 创建一个初始大小为66的int向量 vector<double> vec2(vec1); // 创建一个double型的vec2,并用vec1去初始化vec2 vector<char> vec(10,'k'); // 创建一个含有10个char型数据的vector,并全部初始化为'k' vector<int> vec(10,1);//创建一个初始大小为10的并且值都是1的vector vector<int> vec2(vec1.begin(),vec1.begin()+3);//用向量vec1的第0个到第2个值初始化vec2 int arr[5] = {1, 2, 3, 4, 5}; vector<int> vec(arr, arr + 5); //将arr数组的元素用于初始化vec向量,末尾指针指向结束元素 //的下一个 vector<int> vec(&arr[1], &arr[4]); //将arr[1]~arr[4]范围内的元素作为vec的初始值,不包含arr[4], //原因如上 4.特别的,元素为vector的vector数组 (其实就是vector的二维数组)和vector数组! 如果typename是vector,那么就这么定义vector<vector<int> > vectorname; 注意在相邻的'>'之间要加空格。 这个就像二维数组的定义,其中一维是一个元素是vector的vector数组。可以把vector数组 当作两个维长度都可变的二维数组理解。vector数组的定义vector<typename> Arrayname[arraySize]; 比如,vector<int> vec[66]; 这样Arrayname[0]~Arrayname[arraySize-1]中每一个都是vector容器。 而vector<vector<int> > vectorname不同的地方时,前者的第一维长度已经固定为arraySize了, 后者却是两个维度都可变长的数组。哈哈哈,用你的大脑,发挥空间想象能力,出现了什么图形? 很神奇是不是! 5.vector容器内元素的访问形式 vector一般有两种访问形式:通过下标访问或者是通过迭代器访问。 (1)通过下标访问 和访问普通数组是一样的,一个已经定义的vector<typename> vec的vector容器,直接访问vec[index]就可以了(比如 vec[0],vec[1])。需要注意的一点是,首先这个vec得有size!!!桥黑板!什么意思呢?就是如果一开始你定义了 比如vector<int> vec1;直接使用vec[0]是不对的!因为里面还没有长度啊!开始用的时候我就经常犯这个错误(尴尬) 。所以可以通过下标访问的范围是从0~vec.size()-1. (2)通过迭代器访问 啥叫迭代器啊?好可怕~就理解为指针吧,不去考虑细节,两者是一样的(包括在java中最近遇见的引用,这简直是三胞胎!)。 定义如下: vector<typename>::iterator it;(it就是变量名,一般默认都写成it) 这样it就是一个vector<typename>::iterator 型的变量了(hhh,这个名字好长啊),其中,typename就是定义vector时 写的类型。比如: vector<double>::iterator it; vector<int> vec; vector<int>::iterator it2; it2=vec.begin();(或者合成一条:vector<int>::iterator it2=vec.begin(); ) 这样就得到了迭代器it(or it2),并且可以通过*it来访问vector里的元素。 vector<int> vec; vector<int>::iterator it; for (it = vec.begin(); it != vec.end(); it++)//vector的迭代器不支持it<vec.end()写法,因此循环中只能用it!=end() cout << *it << endl; //或者 vector<int>::iterator it=vec.begin(); for(int i=0;i<vec.size();i++){ printf("%d ",*(it+i));//桥黑板!!在STL容器中,只有vector和string这两个好基友,才允许使用vev.begin()+3这种迭代器加上整 //数的写法,只有这俩。 //从这里可以看出,vec[i]和*(vec.begin()+i)是等价的 } //或者 for (size_t i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl;//见下文分解 } 好了,终于说完访问形式了,可以介绍基本操作啦! 6.vector的基本操作 (1)对容量的操作 得到向量的大小: vec.size(); 得到向量最大可以是多大: vec.max_size(); 重新设置容器size的大小: vec.resize(num); 重新设置容器capacity的大小: vec.reserve(num); 向量真实大小: vec.capacity(); 判断向量是否为空: vec.empty(); 注:关于resize()和reverse(),我觉得记住一点就行了,容器调用resize()函数后, 所有的空间都已经初始化了,所以可以直接访问。比如: vector<int> vet; vec.resize(100); vec[0]=1;//合法语句! 而reserve()函数预分配出的空间没有被初始化,所以不可访问。 推荐一个关于resize()和reserve()写的不错的博客vector中resize()和reserve()区别 (2)修改元素 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值 末尾添加元素: vec.push_back(i)//在末尾添加元素i 末尾删除元素: vec.pop_back(); 任意位置插入元素: vec.insert(it,x); 用来向vector的任意迭代器(见上文)it处插入一个元素x,时间复杂度O(N); 任意位置删除元素: vec.erase(); erease(it)即删除迭代器为it处的元素; erase(first,last)即删除[first,last)内的所有元素;(老美的左闭右开,你懂的) 交换两个向量的元素: vec.swap();//不多讲,用的真的很少。同样,推荐博客vector利用swap()函数进行内存的释放 (3)惊现迭代器 开始指针:vec.begin();末尾指针:vec.end(); //指向最后一个元素的下一个位置指向常量的开始指针: vec.cbegin(); //意思就是不能通过这个指针来修改所指的内容,但还是可以通过其他方式修改的,而且指针也是可以移动的。(用的很少,不妨先忽略吧)指向常量的末尾指针: vec.cend();(同上,不多说) (4)元素的访问 下标访问: vec[1]; //桥黑板!!并不会检查是否越界at方法访问: vec.at(1); //以上两者的区别就是at会检查是否越界,是则抛出out of range异常访问第一个元素: vec.front();访问最后一个元素: vec.back();返回一个指针: int* p = vec.data(); //可行的原因在于vector在内存中就是一个连续存储的数组,所以可以返回一个指针指向这个数组。这是是C++11的特性。(可忽略) (5)一些算法 遍历元素 Cvector<int>::iterator it; for (it = vec.begin();it != vec.end(); it++) cout << *it << endl; //或者 for (size_t i = 0; i < vec.size(); i++) { cout << vec.at(i) << endl; } 元素翻转 C#include <algorithm> reverse(vec.begin(), vec.end()); 元素排序 C#include <algorithm> sort(vec.begin(), vec.end()); //采用的是从小到大的排序 //如果想从大到小排序,可以采用上面反转函数,也可以采用下面方法: bool Comp(const int& a, const int& b) {//固定套路,要加上const,意思是不能修改引用 return a > b; } sort(vec.begin(), vec.end(), Comp); 7.vector的用武之地 (1)储存数据 vector本身可以作为数组使用,而且在一些元素个数不确定的场合可以很好的节省空间。 有些场合需要根据一些条件把部分数据输出在同一行,数据中间用空格隔开。由于输出的数据个数是不确定的,为了跟方便的处理最后一个满足条件的数据后面不输出额外的空格,可以先用vector记录所有需要输出的数据,然后一次性输出。 有强大的方法可以调用(妈呀,java学多了,请不要喷我,暂且就叫方法吧,介绍如上vector的基本操作(1)~(4)) ( 2 )用邻接表存储图 使用vector实现邻接表可以有效避免指针,而且更容易把握。 哈哈哈,终于结束啦(喝口水)。好了,说了这么多,当然废话也不少~~来几道题目吧!PAT A1039. Course List for Student (25) PAT A1047. Student List for Course (25) 参考:C++ STL之vector用法总结《算法笔记》(胡凡,曽磊)

优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(二)——set

二、set 1.set的自我介绍 <li>set意思是集合,从初中就接触到了集合的概念,真是的好东西。set是一个内部自动有序且不含重复元素的容器。</li> <li>set是一种关联式容器,是用来存储同一种数据类型的数据类型,有点绕口,就是sety也就是集合里里面要不然全部装int型的要不然全部装double型的要不然....就是这个意思。并且能从这个同一种数据类型构成的集合中取出元素,而且set中的每个元素都是唯一的,不能重复,好像是数学里集合概念中的唯一性(哈哈哈,强大的数学功底)。更令人欣慰的是,能根据元素的值进行自动排序。</li> <li>一个集合(set)是一个容器,它其中所包含的元素的值是唯一的。这在收集一个数据的具体值的时候是有用的。集 合中的元素按一定的顺序排列,并被作为集合中的实例。如果你需要一个键/值对(pair)来存储数据,map是一个更好的选择。一个集合通过一个链表来组 织,在插入操作和删除操作上比向量(vector)快,但查找或添加末尾的元素时会有些慢。(原因后文简单说说)</li> <li>要注意的是,set中书元素的值不能被直接改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树,即一种自平衡二叉树(以后会讲到啥叫平衡二叉树~~):红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。</li> 2.set的定义 <li>单独定义一个set:</li> set<typename> setname; <li>其定义和大部分STL的定义都差不多,这里的typename依然一样可以是任何基本类型,比如int,double,char,结构体啊,还有STL的标准容器vector,set,queue啊等等。</li> <li>需要注意的是,比如<em>set&lt;vector&lt;int&gt; &gt; setname;</em>两个'&gt;‘之间一定要加上空格,否则会编译错误,原因是会误以为位移运算(详见上篇)。</li> <li>特别的,set数组:</li> set<typename> Arrayname[arraySize]; 比如,set<int>a[100];定义了一个set型的数组,数组中每一个数都是一个集合,每一个集合里都是int型的值。 3.set容器内元素的访问形式 <li>只有一种!</li> hhh,选择 困难症的同学是不是很开森呢? 只能通过迭代器访问(啥叫迭代器?详见上篇): set<typename>::iterator it;(这个也不多说了,和vector是一模一样滴) 比如,set<int>::iterator it; set<double>::iterator it; 同样的,和vector一样可以通过*it来访问set里的元素啦,忍不住再唠叨一句,迭代器就是指针。 4.set中的基本操作 <li>insert(x): 插入元素,并且自动递增排序噢,而且去重,时间复杂度O(logN),N为set中元素的个数。</li> <li>insert(first,second): 将定位器first到second之间的元素插入到set中,返回值是void</li> <li>find(value): 返回set中对应值为value的迭代器,时间复杂度未O(logN)!!后文会重点讲(见下文5.set的注意点和优良特性),有助于加深理解O(logN),举一反三,以后也不过多强调了qwq。</li> <li>begin(): 返回set容器的第一个元素//桥黑板!!begin() 和 end()函数是不检查set是否为空的,使用前最好使用empty()检验一下set是否为空</li> <li>end(): 返回set容器的最后一个元素</li> <li>clear(): 删除set容器中的所有的元素//时间复杂度O(N)</li> <li>empty(): 判断set容器是否为空</li> <li>max_size(): 返回set容器可能包含的元素最大个数</li> <li>size() : 返回当前set容器中的元素个数//时间复杂度O(1),贼快!</li> <li>rbegin: 返回的值和end()相同</li> <li>rend(): 返回的值和rbegin()相同</li> <li>count(): 顾名思义嘛,用来查找set中某个某个键值出现的次数。但是,这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。(小技巧)</li> <li>erase(iterator): 删除迭代器iterator指向的值//时间复杂度O(1),贼快!注意和erase(value)不同噢</li> <li>erase(first,second): 删除定位器first和second之间的值(美国人的思维是左闭右开,最后一次强调)</li> <li>erase(value): 删除值为value的元素,时间复杂度O(logN)//桥黑板!!set中的删除操作是不进行任何的错误检查的,比如定位器的是否合法等等,所以用的时候自己一定要注意。</li> <li>lower_bound(key_value): 返回第一个大于等于key_value的定位器</li> <li>upper_bound(key_value): 返回最后一个大于等于key_value的定位器//二分啦!</li> 5.set的注意点和优良特性 (加深对set的理解,初学者可以先跳过此部分) <li>不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,则插入新元素</li> <li>不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取,而且从迭代器角度来看,元素值是常数</li> <li>元素比较动作只能用于型别相同的容器(即元素和排序准则必须相同) 因为set中重写比较函数的用的真还不多,所以就不细细的讲了,等降到后面的priority_queue的时候,我会重新讲一下结构体的比较函数(其实也叫优先级设置)。 从原型可以看出,可以看出比较函数对象及内存分配器采用的是默认参数,因此如果未指定,它们将采用系统默认方式,另外,利用原型,可以有效地辅助分析创建对象的几种方式。 之前提到了set(map也一样哈)的插入删除效率比用其他序列容器高,简单的讲set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。需要插入或删除,只要改变指针指向的节点就可以啦。(其实本质上还是因为set自带的红黑树的内部结构,就是外挂啊。气哭!STL容器各个都是身怀绝技) set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。 6.set的常见用途 set最主要的作用是自动去重,并在没有写比较函数的情况下,默认按升序排序,因此碰到需要去重但是却不方便直接开数组的情况,可以尝试用set来解决噢。 set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。 7.练习题,桥黑板!! PAT A1063. Set Similarity (25) 参考:C++中关于set的自定义排序函数的书写,STL中set容器的一点总结 《算法笔记》(胡凡,曽磊)

优秀的个人博客,低调大师

算法学习之路|用C++刷算法会用到的STL(三)——string

三、string 1.string的自我介绍 在C语言中,一般使用字符数组 char str[]来存放字符串,很麻烦!在C++中加入了string类型,可以理解为元素为char型的vector,string对字符串的需求功能进行了封装,使得操作简单,不容易犯错。 使用string需要添加的头文件是#include<string>(桥黑板!!string.h(同cstring)和string是不一样的头文件)。当然还要加上using namespace std;这一句的。 2.string的定义 定义的方式和基本数据类型相同,在string后面加上变量名即可: string str; 如果要初始化,可以直接给string类型的变量进行赋值: string str="abcd"; 3.string容器内元素的访问形式 注:之前说过C++容器中有一对好基友,没错! 就是string和vector,只有他俩可以使用直接对迭代器进行加减某个数字,如str.begin()+3 <li>通过下标访问 即可以像访问char型数组一样去访问string,比如:#include<stdio.h>#include<string>string str="hahah";printf("%c",str[2]);//输出 h但是要读入和输出整个字符串,则只能用cin和cout: [php]#include#includeusing namespace std;int main(){ string str; cin>>str; cout<<str;//相当于,printf("%s\n",str.c_str());即将string类型用c_str()变为字符数组 return 0;//并不推荐第二种写法!了解即可 }[/php] <li>通过迭代器访问 因为string不像其他STL容器一样需要参数,因此迭代器的定义很简单:string::iterator it;这样就得到了迭代器,并且可以通过*it来访问string中的每一位元素:for(string::iterator it=str,begin();it!=str.end();it++){printf("%c",*it);} 4.string中的基本操作 (真的只是基本操作,也是常用的,文末推荐几个博客,有更多骚操作!!!里面写的很详细,感兴趣的朋友可以深入研究,string真的很强大,之前说过, STL各个都是武林高手,身怀绝技的啊!) (1)operator+= 这是string的加法,可以将两个string直接拼起来!,比如: string str1="i",str2="love you!",str3; str3=str1+str2;//cout得到str3: i love you!(single dog 一万点伤害(捂脸)) str1+=str2;//将str2直接拼接到str1上,得到str1:同上(捂脸)(捂脸) (2)compare operator 简单说一下,即两个string类型可以直接使用==,!=,<=等比较大小,比较规则为字典序,从两个string的首位开始比较,遇到不一样的即按字典序比较返回结果。但比如 ,str1="aa",str2="aaa",则是str1<str2,不多介绍,用的时候试一下就自然清楚啦。 (3)lenth()/size() 可以认为两个基本相同,时间复杂度都是O(1),返回string的长度,即存放的字符数。比如,str=“aa",返回2。 (4)insert() string的insert()函数写法很多,实际上不只insert,赋值,连接,比较查找等函数都很多,自然,功能也很细节化,很完善,不常用,这里只介绍算法需要用到的,就上上文所说的,文末会推荐一个非常好的博客,如果又需要,可以去仔细研究。 <li><em>insert(pos,string),</em>在pos号位置插入字符串string。</li> string str="abc",str2="xyz"; str.insert(1,str2);//结果str:axyzbc <li><em>intsert(it,it2,it3)</em>,it为原字符串欲插入的位置,it2和it3为待插入字符串的首位迭代器,用来表示串[it2,it3)将被插在it的位置上,比如: string str="abcxyz",str2="opq";str.insert(str.begin()+3,str2.begin(),str2.end());//桥黑板!!再次强调,只有vector和string这两个好基友迭代器加数字的形式!!结果,str:abcopqxyz (5)erase() 删除单个元素: str.erase(it),it为需要删除的元素的迭代器。 删除一个区间内的所有元素: str.erase(first,last),first未删除区间的起始迭代器,last为需要删除区间的末尾迭代器的下一个指针,也即[first,last)。 str.erase(pos,length),其中pos为需要删除的其实位置,length为删除的字符个数。 (6)clear() clear()用来清空string中的数据,时间复杂度O(1)。 substr() substr(pos,len)返回从pos号位开始,长度为len的子串,时间复杂度O(len)。(注:本文只有it才是迭代器,pos是下标) (7)string::npos string::npos是一个常数,其本身的值为-1,但由于是 unsigned_int类型,因此呢,实际上也可以认为是unsigned_int类型的最大值。 string::npos用以作为find函数(如上文所述,find即查找函数非常多,详见下文推荐博客!)失配时的返回值。 可以认为string::npos等于-1或者4294967295。 (8)find() <li>str.find(str2),当str2是str的子串时,返回其在str中第一次出现的位置;如果str2不是str的子串,那么返回上文提到的string::npos(也就是-1和那个无符号整型的最大值啦)。</li> <li>str.find(str2,pos),从str的pos号位开始匹配str2,返回值同上。时间复杂度为O(nm),n,m为str,str2的长度。</li> (9)replace() <li><em>str.replace(pos,len,str2)</em>把str从pos号位开始,长度为len的子串替换为str2。</li> <li><em>str.replace(it1,it2,str2)</em>把str的迭代器[it1,it2)范围的子串换为str2。</li> <li>时间复杂度<em>O(str.length())</em>。</li> 5.string的优良特性 C++ 标准库中的string类型 支持可变长度的字符串,提供了很多有用的操作 标准库将负责管理与存储字符相关的内存。 平均来说 使用string类型的程序执行速度比C风格字符串快很多 而且不容易出错 ;以前的很多地方C语言程序是用C语言风格字符串写的 没有用标准库类型string 可能不具备有移植性 两者都要掌握 现代C++程序员应更多地使用string。 6.string的用途 处理“串”的问题。。。 来道题练练手: PAT A1060. Are They Equal (25) 注:题意不难,编码较为复杂,但也是练string的好题目!加油吧 PAT A1001. A+B Format (20) 注:此题解法很巧妙,简洁,推荐66姐的博客1001. A+B Format (20)-PAT甲级真题 参考:《算法笔记》(胡凡,曽磊) 推荐博客:标准C++中的string类的用法总结 。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册