Java 泛型:List,Map,Set,Collections

发布时间 2023-12-15 01:54:42作者: 粥粥alg

第一章:集合的概念

1.1 集合的概念

集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容:

  • 接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象。
  • 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
  • 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
    除了集合,该框架也定义了几个 Map 接口和类。Map 里存储的是键/值对。尽管 Map 不是集合,但是它们完全整合在集合中。

第二章:Java 泛型

2.1 泛型的使用

我们编写了一个泛型类 Containers 用来存储数据:

名称 介绍
Containers.T 保存数据的位置
Containers.set(T t) 将传入的数据保存下来
Containers.get() 获取保存的数据
请在 Solution 类中的 initContainers() 方法中编写您的代码,将传入的数据保存到 Containers 中,并将其返回。
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;

public class Solution<T> {

    public Containers<T> initContainers(T t){
        // write your code here
//观察到返回类型是一个Containers类,则必然需要创建一个Containers的对象
        Containers containers = new Containers();
//调用该对象的set方法对成员变量进行初始化
		containers.set(t);
//最后返回该对象即可
        return containers;
    }
}

2.2 泛型类的使用

请您设计一个简单的泛型类 Solution,泛型类中包含一个变量 var ;方法 setVar 设置变量 var 的值; 方法 getVar 获取 var 的值。

请您对已提供的 Solution 类做出修改,使其满足上述要求。

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

public class Solution<T> {
	private T var;
    public void setVar(T var){
        this.var = var;
    }
     public T getVar(){
        return this.var;
    }
}

2.3泛型数组的使用

请您对 Solution 类进行修改,使其满足如下条件:

  • Solution 类中,包含一个可以接收任意类型的数组 arr;

  • 在创建 Solution 对象时,可以指定数组 arr 的类型;

  • 创建一个方法 initArrData(),传入一个与 arr 相同类型的数组 src,并将 src 中的值复制到 arr 中;

  • 创建一个方法 getArr(),返回 arr。

我们已经帮您创建了 Solution 类的构造方法,您可以在这个方法中初始化数组 arr 的大小。您需要使用泛型来实现上述要求的功能(不能使用 Object),请在 // write your code here 下写下您的代码。

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;

public class Solution <T>{

    T[] arr;

    public Solution(Class cls, int size) {
        this.arr = (T[])Array.newInstance(cls, size);
    }

    public void initArrData(T[] src){
        for(int i=0;i<arr.length;i++){
            src[i]=arr[i];
        }
    }

    public T[] getArr(){
        return arr;
    }
}

2.4 数组复制

请在 Solution 类中定义一个非静态方法 copy(),用来把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中,并且不用指定方法的返回值。

我们会调用您写的 copy 方法,并传递两个参数,第一个参数是原数组(有值),第二个是目标数组(无值),您需要将第一个数组中的值复制到第二数组中。

public class Solution {
	// write your code here
	
  public <T> T[] copy(T[] a,T[] b){
	  for (int i = 0; i < a.length; i++) {
		b[i] = a[i];
	  };
	  return b;
  }

}

2.5 两数之和 II

对于任何程序员来说,两数之和 都是一道极其熟悉的题目:求两个数的和,并返回求和之后的结果。

今天我们把这道题目升级一下,只不过两个数为任意类型的数字,您需要在 Solution 类中创建一个方法 numberSummation(),这个方法可以传入任意类型的两个数字(Number),并将计算结果以 Double 类型返回。

import java.math.BigDecimal;
import java.util.*;

public class Solution {
	// write your code here
	public<T> Double numberSummation(T num1,T num2){
		BigDecimal num=new BigDecimal(num1.toString()).add(new BigDecimal(num2.toString()));
		
		return num.doubleValue();
	}
}

2.6 泛型的上下限

我们创建了一个 Info 的泛型类,用来存储数据。

名称 介绍
Solution.upperLimit() 接收一个 Info,只能接收 Number 及其 Number 的子类,并获取 Info 中的值返回
Solution.lowerLimit() 接收一个 Info,只能接收 String 或 Object 类型的泛型,并获取 Info 中的值返回
Info.T 保存数据的位置
Info.set(T t) 将传入的数据保存下来
Info.get() 获取保存的数据

请您在 Solution 类中实现方法upperLimit() 和 lowerLimit() 的功能。

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;

public class Solution {

    public Number upperLimit(Info<? extends Number> s){
        return s.get();
    }

    public Object lowerLimit(Info<? super String> s){
        return s.get();

    }
}

第三章:List

3.1 List 集合

从 集合的概念 章节中,我们可以知道 List 是一个接口,它是最基础的一种集合:它是一种有序列表。它的常用子类包括:

  • ArrayList:基于动态数组实现,支持随机访问。

  • LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。

  • Vector:和 ArrayList 类似,但它是线程安全的。

  • Stack:它实现了一个标准的后进先出的栈,是 Vector 的子类。

  • CopyOnWriteArrayList:一个线程安全的 ArrayList。

3.2 字母排序

现给你一段英文字母,你需要将这段英文字母存储在集合中,并在集合中将这段英文字母按照字母表的顺序重新排列(不区分大小写),将重新排列的英文字母打印在标准输出流(控制台)。

import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

public class Solution {
	// write your code here

	public List<String> sort(String letter) {
        String[] split = letter.split("");
        Arrays.sort(split,String.CASE_INSENSITIVE_ORDER);
        return Arrays.asList(split);
	}

}

3.3 创建 ArrayList 集合并添加数据

请编写代码,创建一个 ArrayList 集合,向集合中添加两条数据并且返回该集合。

在本题的 Solution 类中有个 createList 方法,该方法有两个 String 类型的参数 str1、str2,str1 代表向 ArrayList 集合中添加的第一条数据,str2 代表向 ArrayList 集合中添加的第二条数据。该方法要创建一个 ArrayList 集合,向集合中添加两条数据并且返回这个集合。返回值为 ArrayList 类型。


import java.util.ArrayList;


public class Solution {
    public ArrayList<String> createList(String str1, String str2) {
        // 创建 ArrayList 集合对象,并指定集合存储 String 类型的数据
        ArrayList<String> list = new ArrayList<String>();
        // 调用 add 方法添加元素
        list.add(str1);
        list.add(str2);

        return list;
    }
}

3.4 筛选集合中的元素

李四在 Main.java 文件中定义了集合 blist,向该集合中存储了十个正整数,并在 main 方法中调用了 watch 方法,请你在 Solution 类中编写 watch 方法,要求将输入的十个数字中的偶数存储在另一个新定义的一个集合中。现给定十个正整数,在正确代码运行结束后,应当在标准输出流(控制台)中打印出用来存储偶数的新集合。

import java.util.ArrayList;

class Solution {
    public static void watch(ArrayList<Integer> bList) {
       ArrayList<Integer> cList = new ArrayList<>();
       for (Integer integer : bList) {
           if (integer % 2 == 0) {
               cList.add(integer);
           }
       }
       System.out.println(cList);

}

3.5 删除集合中的最小值

你的代码需要从标准输入流(控制台)中录入多个整数,每个数字之间用空格符号间隔,以输入数字 0 作为结束输入,将这些数据存储至集合中,再将集合转为数组,按照元素从小至大的顺序排列好,将排好序的数组转为一个新的集合,删除集合中最小的元素,将新集合输出。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.*;
class Solution {
	// write your code here
		
	public ArrayList<Integer> sort() {
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		ArrayList<Integer> alist = new ArrayList<>();
		while(num != 0){
			alist.add(num);
			num = sc.nextInt();
		}
		Collections.sort(alist);
		alist.remove(0);
		return alist;
	}

}

3.6 线程安全的 List

请通过 Solution 类的 getList 方法返回一个 List 的实现类,要求是线程安全的,你可以自己设计一个同步的 List 实现类进行返回。
输入是一个整数 n,我们会向返回的 List 中添加 n * 10 个数据,并输出 List 中的数据个数。

import java.util.*;

public class Solution {
    public List<Integer> getList() {
        // write your code here
        Vector<Integer> vector = new Vector<>();
        return vector;
    }

}

3.7 LinkedList 去除重复元素

给定六个字符串,将这些字符串存放在 LinkedList 中,然后将 LinkedList 中重复的元素删除,最后将 LinkedList 中所有元素用迭代器方式打印在标准输出流(控制台)中,请你帮助她完成这道题目。

import java.util.Iterator;
import java.util.LinkedList;

class Solution {
	
	public static LinkedList<String> Weighting(LinkedList<String> list) {
		//创建一个集合存储去重复后的元素
		LinkedList<String> linkedList = new LinkedList<String>();
		//使用迭代器判断是否有下一个数据
		Iterator<String> iterator = list.iterator();
		while(iterator.hasNext()){
			String str = iterator.next();
			if(!linkedList.contains(str)){
				linkedList.add(str);
			}
		}
		return linkedList;
	}

}

3.8 LinkedList 实现字符串反转输出

你的代码需要从标准输入流(控制台)中读取一段字符串,利用 LinkedList 中的方法将该字符串反转输出在标准输出流(控制台)中。

import java.util.LinkedList;
import java.util.Scanner;
import java.util.Collections;

public class Main {

	public static void main(String[] args) {
		
		//write your code here
		Scanner sc=new Scanner(System.in);
		String str=sc.next();
		LinkedList<Character> list=new LinkedList();
		for(int i=0;i<str.length();i++){
			list.add(str.charAt(i));
		}
		Collections.reverse(list);
		for(char c:list){
		System.out.print(c);
		}

	}
}

3.9使用队列拦截数据

有一个 int 数组,包含 n 个数且有序,分别是 1、2、···、n,它们被队列 Queue 拦截(进入队列,数据也可能不进入队列)后得到一串序列。现在给你一串 1 ~ n 的序列,请你判断该序列是否是被队列 Queue 拦截后得到的序列,并通过 isOutByQueue 函数返回结果。
例:

  • 序列:[2, 3, 1, 4]
  • 根据序列可以知道数据个数为 n = 4,有序数组为:[1, 2, 3, 4]
  • 该序列可以通过以下方法得到:
    • 有序数组经过队列 Queue 时,1 被队列拦截住(进入队列),2 和 3 未被拦截,得到序列:[2, 3],队列中数据:[1];
    • 接着 1 在数字 4 进入序列前,离开队列 Queue 进入序列,得到:[2, 3, 1];
    • 最后数字 4 进入序列,得到:[2, 3, 1, 4]

可以得到,序列:[2, 3, 1, 4] 是被队列 Queue 拦截后得到的序列

import java.util.*;

public class Solution {
    public boolean isOutByQueue(int[] nums) {
        // write your code here
        Queue<Integer> q = new LinkedList<>();
        int pre_max = 0;

        for(int elem:nums){
            if(elem>pre_max){
                for(int i=pre_max+1;i<elem;i++){
                    q.add(i);
                }
                pre_max = elem;
            }else if(q.isEmpty() || elem!=q.peek()){
                return false;
            }else{
                q.poll();
            }
        }
        return true;
    }

}

3.10使用栈拦截数据

import java.util.*;

public class Solution {
    public boolean isOutByStack(int[] nums) {
        // write your code here
        if(nums.length == 1){
            return true;
        }
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        int i = 0;
        while(i < nums.length){
            if((i+1) != nums[j] && (i+1) < nums[j]){
                stack.push(i+1);
                i += 1;
            }else if((i+1) == nums[j]){
                j += 1;
                i += 1;
            }else if((i+1) > nums[j]){
                while (!stack.isEmpty()){
                    if(stack.peek() == nums[j]){
                        stack.pop();
                        j += 1;
                    }else if(stack.peek() > nums[j]){
                        return false;
                    }else{
                        break;
                    }
                }
            }
            
        }
        while (!stack.isEmpty() && j < nums.length){
            if(stack.peek() == nums[j]){
                stack.pop();
                j += 1;
            }else{
                return false;
            }
        }
        return true;
    }

}

3.11 将表达式转换为逆波兰表达式

给定一个字符串数组,它代表一个表达式,返回该表达式的逆波兰表达式。(去掉括号)

class Solution:
    """
    @param expression: A string array
    @return: The Reverse Polish notation of this expression
    """
    def convertToRPN(self, expression):
        # write your code here
        def getPriority(item):
            if item in "*/":
                return 3
            if item in "+-":
                return 2
            if item == ")":
                return 1
            return 0
        res = []
        stack = []
        for item in expression:
            if item == "(":
                stack.append(item)
            elif item == ")":
                while stack and stack[-1] != "(":
                    res.append(stack.pop(-1))
                if stack:
                    stack.pop(-1)
            elif item.isdigit():
                res.append(item)
            else:
                priority = getPriority(item)
                while stack and getPriority(stack[-1]) >= priority:
                    res.append(stack.pop(-1))
                stack.append(item)
        while stack:
            res.append(stack.pop(-1))
        # print(res)
        return res

第四章:Map

4.1 向 Map 中添加数据

我们向 putMap() 传入一个 Map,请你向这个 Map 中添加数据,数据是将一年的一月 到 十二月(January to December)作为键,每个月的天数作为值(2 月份天数定为 28),请实现该方法。

一月:January
二月:February
三月:March
四月:April
五月:May
六月:June
七月:July
八月:August
九月:September
十月:October
十一月:November
十二月:December

import java.util.*;

public class Solution {
    public static void putMap(Map<String, Integer> map) {
        // write your code here
        map.put("January", 31);
        map.put("February", 28);
        map.put("March", 31);
        map.put("April", 30);
        map.put("May", 31);
        map.put("June", 30);
        map.put("July", 31);
        map.put("August", 31);
        map.put("September", 30);
        map.put("October", 31);
        map.put("November", 30);
        map.put("December", 31);
    }

}

4.2 存在重复数字的数组

给定一个 int 数组,判断数组中是否存在重复的数字。

如果存在一数字在数组中出现至少两次,则函数返回 true
如果数组中每个元素都不相同,则返回 false

import java.util.*;

public class Solution {
    public boolean containsDuplicate(int[] nums) {
        // write your code here
        int a= nums.length;
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i],nums[i]);
        }
        if (map.size()==a){
            return false;
        }else {
            return true;
        }
    }
}

第五章 Set

5.1 HashSet

HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。

  • HashSet 允许有 null 值。

  • HashSet 是无序的,即不会记录插入的顺序。

  • HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。

  • HashSet 实现了 Set 接口。

5.2 创建 HashSet 集合并添加数据

请编写代码,创建一个 HashSet 集合,向集合中添加四条数据并且返回该集合。

HashSet 不允许存放重复值。
HashSet 是无序的,即不会记录插入的顺序。

在本题的 Solution 类中有个 createHashSet 方法,该方法有四个 String 类型的参数 str1、str2,str3,str4,它们分别代表向集合中添加的四条数据。该方法要创建一个 HashSet 集合,向集合中添加四条数据并且返回这个集合。返回值为 HashSet 类型。

import java.util.HashSet;

public class Solution {
    public HashSet<String> createHashSet(String str1, String str2, String str3,
        String str4) {
        HashSet<String> set = new HashSet<>();
        set.add(str1);
        set.add(str2);
        set.add(str3);
        set.add(str4);
        return set;
        
    }
}

5.2 字符串去重且保证顺序

在类 Solution 中,含有名为 handle 的方法,传入任意非空的字符串,要求返回去除重复元素的字符,且要保证与原先的顺序相同。


import java.util.LinkedHashSet;


public class Solution {
   
    public String handle(String str) {
        LinkedHashSet<String> set = new LinkedHashSet<String>();
        // 将字符串进行拆解后,放入set中 保证了插入顺序
        for (int i = 0; i < str.length(); i++) {
            set.add(str.charAt(i) + "");
        }

        String res = "";
        // 遍历 set 将字符串拼接起来
        for (String s : set) {
            res += s;
        }

        return res;
    }
}

5.3 数组合并

给定两个数组 arr1 和 arr2,请您将两个数组合并成一个有序的数组,并去除数组中的重复数字。

import java.util.*;

public class Solution {

    public int[] mergeArray(int arr1[], int arr2[]) {
        HashSet<Integer> hs=new HashSet<>();
     
        for(int i=0;i<arr1.length;i++){
            hs.add(arr1[i]);
        }
        for(int j=0;j<arr2.length;j++){
            hs.add(arr2[j]);
        }
        Object[] myarr=hs.toArray();
        int[] myInteger=new int[myarr.length];
        for(int i=0;i<myarr.length;i++){
           myInteger[i]=(int)myarr[i];
        }
        Arrays.sort(myInteger);
       return myInteger;
    }
}

第六章 其他