11.15顺序表

0.泛型遗留的一些知识点

 

宏观角度来看

数组不能整体转换,内部元素转换不了

微观角度

 

 

一.包装类(Wrapper Class)

Object 引用可以指向任意类型的对象,但有例外出现了,8 种基本数据类型不是对象,那岂不是刚才的泛型机制要 失效了?

实际上也确实如此,为了解决这个问题,java 引入了一类特殊的类,即这 8 种基本数据类型的包装类,在使用过程 中,会将类似 int 这样的值包装到一个对象中去

1 基本数据类型和包装类直接的对应关系

 

基本就是类型的首字母大写,除了 Integer 和 Character

2 包装类的使用,装箱(boxing)和拆箱(unboxing)

装箱,装包:把简单类型->包装类类型

拆箱,拆包:把包装类类型->简单数据类型的数据

1.隐式的拆包,装包

 

2.显式的拆包,装包

 

 

 

3.面试问题

 

 

为什么一个大一个小

 

可以看到,如果i在这个范围

 

 

也就是[-128,127]

他就会返回一个缓存数组下标为

 

也就是如果你是0那么就是0+128就是128

这个数组的范围就是128+127=255

如果他们在这个范围.那就代表都是数组下的一个元素.所以地址会一样

但是如果不是,就会new一个新对象

 

自然地址不一样 了

三.List 的使用

 

1.LIst和ArrayList的父类

 

 

2.顺序表的初始化

学习任何一个类都要先了解他的构造方法

 

 

3.顺序表的打印

1.直接用写好的toString打印整个顺序表

 

//1.利用已经重写好的toString
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("bit");
list2.add("haha");
System.out.println(list2);
System.out.println("================");

2.遍历顺序表,用get方法找到每个下标下对应的元素

因为顺序表底层就是个数组

for (int i = 0; i < list2.size(); i++) {
    System.out.print(list2.get(i)+" ");
}
System.out.println();

3.迭代器打印

因为顺序表的iterator方法返回Iterator 就用这样的类接收

 

 

构建一个循环,it刚开始会放在数组前面一个位置,如果下一个有,就会往前遍历,直到下一个没有元素.

System.out.println("========迭代器List相关打印==========");
        ListIterator<String> it2 = list2.listIterator();
        while (it2.hasNext()) {
            System.out.print(it2.next()+" ");
        }

4.foreach循环

只要是collection下的数据结构 都可以用for-each循环

//for-each循环
System.out.println("==================");
for (String s:list2) {
    System.out.print(s+" ");
}

5.迭代器List相关打印

这个迭代器是List自带的

System.out.println("========迭代器List相关打印==========");
        ListIterator<String> it2 = list2.listIterator();
        while (it2.hasNext()) {
            System.out.print(it2.next()+" ");
        }
//1.利用已经重写好的toString
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
list2.add("bit");
list2.add("haha");
System.out.println(list2);
System.out.println("================");
//2.遍历整个顺序表,利用顺序表的get方法找到每个下标
for (int i = 0; i < list2.size(); i++) {
    System.out.print(list2.get(i)+" ");
}
System.out.println();
//3.迭代器打印
System.out.println("========迭代器打印========");
Iterator<String> it=list2.iterator();
while(it.hasNext()){
    System.out.print(it.next()+" ");
}
//for-each循环
System.out.println("==================");
for (String s:list2) {
    System.out.print(s+" ");
}
//LIst迭代器
System.out.println("========迭代器List相关打印==========");
        ListIterator<String> it2 = list2.listIterator();
        while (it2.hasNext()) {
            System.out.print(it2.next()+" ");
        }

4.两个迭代器的区别

 

注意:在使用迭代器的方法的时候,需要先遍历元素,再可以使用,非常就会抛出异常

 

先建立一个变量接收遍历的值

add函数只有LIst迭代器有

 

 

 

 

 

把改成这个就可以了

5.add方法

 

6.subList和set方法

Java中只要是from和to的都是左臂右开的

 

 

并且并不是新建一个数组,而是将引用指向了对应的下标

 

原数组还是没有变换

二.add(index.e element)方法

 

 

 

如果范围检查不对.就会抛出异常

第二个方法,把确定容量,检查容积,扩容都放在一个方法里了.

第三个方法就是移动元素,

 

这个方法是一个C++底层实现的方法我们看不到原理,大致就是构建一个新的数组,把index的元素移动到index+1.然后循环.再把新的数组的元素放到老的元素里.

2.remove方法

 

 

三.详解ArrayList无参构造方法

 

当new一个新对象的时候没有参数的时候,就会调用无参构造方法

这个时候的数组就会分配给一个数组

 

 

追随底层,居然发现他是一个空的

这个时候我们就疑惑了,如果他是一个空的,那么放元素的时候,.难道不会数组越界吗

然后我们就开始调查add方法

 

在add方法的第一行我们发现他调用了一个方法

叫确保内部容积方法

 

在点进去,发现他这个时候调用了两个方法

 

一个是括号里的(预测容积方法)

 

还有一个是调用它的(一个确定的容积)

 

那我们先从括号里的开始调查

 

这里我们发现.如果就是一个空数组,那么就会返回一个最大值,这个minicapacity再一开始我们就知道就是size+1.也就是1.很明显比不过默认的大小,那就会返回一个10

 

所以这个方法的括号里就是10

 

这里我们发现,第一行表示修改顺序表的次数.这里就解释了之前为什么在LIst构造器会报错

因为之前返回了10.数组的长度为0.所以进入了if语句这里我们再次进入grow方法

 

 

这里让新的容量扩容了1.5倍.

因为本身就是0扩容了还是0.所以就进入了第一个if语句

让新的容量变成了10

第二个if语句

这个数字是及其大的.

 

 

会返回一个很大的\数,我们这里并没有大于他

方法的最后一句话,就是让这个数组的容积变成了新的

 

也就是10

 

add默认尾插

总结:在顺序表插入元素的时候

首先先判断下标是否合法

然后再判断是否需要扩容

这个扩容包含了三步

第一步 :预估所需要的容量

 

第二步:用所需要的容量和已有的容量对比

 

第三步满了就扩容

 

四.订正

 

A基本数据类型不是包装类型的简写

C浮点数默认是double

D基本数据类型不能调用方法

 

A错误:ArrayList中的元素不一定有序,ArrayList没有要求里面的元素必须有序,可能有序也可能不有序

B正确:ArrayList中的元素可以通过下标修改

C错误:ArrayList中的元素每一要求必须要唯一,可以唯一也可以重复

D错误:ArrayList中的元素是通过下标访问的,而不是通过key

故正确应该选择B

HashMap中存放的元素类型为键值对,注意内置类型不能直接来实例化HashMap,必须要找其对应的包装类型

泛型的语法上必须匹配。使用子类或超类,也必须使用通配符来匹配,比如这里要方法参数需要定义为List即可接受List的对象

 

 

 

 

注意 : 后面才是一个表达式

五.字符集合

 

这道题我当时做的时候用了最笨的方法,本来都是做出来了.因为不习惯牛客的,不会弄多组输出,最后一分都没有,非常可惜.本来应该满分的.

所以一定要养成习惯,

1.我的方法

因为字符串本质就是个字符数组,我们就利用转数组方法转为数组

遍历整个数组,从第一个下标开始遍历,然后遍历除了第一个下标的所有的下标如果如果跟第一个相同就置为1,

因为是字母所以可以置为数字.然后一个回合下来,再找第二个元素,把第二个元素往后开始遍历,如果有跟第二个相同的就置为数字1

最后打印如果不等于字符1.就不打印

这里注意一下,最后要换行.否则就会出现错误.(血泪)

 

牛客这里也不会提示,只是一直说不符合要求

public class Main {//方法1
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextLine()) {
            String s = in.nextLine();
            char[] chars = s.toCharArray();
            int len = chars.length;
            for (int i = 0; i < len - 1; i++) {
                for (int j = i + 1; j < len; j++) {
                    if (chars[j] == chars[i]) {
                        chars[j] = '1';
                    }
                }
            }
           // System.out.println();
            for (int a = 0; a < len; a++) {
                if (chars[a] != '1') {
                    System.out.print(chars[a]);
                }
            }
            //System.out.println();
        }
    }
}

2.利用StringBuilder类

思路:先循环输入输出

 

再构建一个方法,

利用StringBuilder的拼接方法.

利用charAt方法遍历每个字母,

但是发现StringBuilder没有contains方法就是是否包含某个元素

那我们可以让StringBuilder先转换为字符串再找.但是之前遍历的是一个字母不是字符串就可以再后面加一个""变成字符串

 

这个方法我觉得就是要对字符串的各个方法非常熟悉

public class Main {//方法2
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str = scanner.nextLine();
            String ret = func(str);
            System.out.println(ret);
        }
    }
    public static String func(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if (!sb.toString().contains(ch + "")) {
                sb.append(ch);
            }
        }
        return sb.toString();
    }
}

方法3 哈希表

定义一个整形数组,初始化为0,来标记这个字符是否出现过,如果出现过就标记为1,下次同样的字符来了,只要不是0,就不是我想要的/

就把字母定为数组下标

因为字符对应ASCII码有对应 的数字,所以可以直接放上去

public class Main {//方法3
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String str = scanner.nextLine();
            func1(str);
            // System.out.println(ret);
            System.out.println();
        }
    }
    public static void func1(String str) {
        int[] arr = new int[58];
        for (int i = 0; i < str.length() ; i++) {
            char ch = str.charAt(i);
            if (arr[ch - 65] != 1) {
                arr[ch - 65] = 1;
                System.out.print(ch);
            }
        }
    }
}

 

 

list

 

父类引用子类对象,只能引用父类自己的方法,除非子类重写,那么就会覆盖父类的同名方法,优先用子类的方法

练习1

 

class Student{
  private String name;
  private String calsses;
  private double score;

    public Student(String name, String calsses, double score) {
        this.name = name;
        this.calsses = calsses;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCalsses() {
        return calsses;
    }

    public void setCalsses(String calsses) {
        this.calsses = calsses;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", calsses='" + calsses + '\'' +
                ", score=" + score +
                '}';
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        ArrayList<Student> list=new ArrayList<>();
        list.add(new Student("sun","Java103",95.8));
        list.add(new Student("yi","Java104",90.8));
        list.add(new Student("qing","Java102",95.9));
      /**  for (Student s:list) {
            System.out.println(s);
        }*/
        System.out.println(list);

    }

练习2

 

1.我的方法-string方法

遍历两个数组,有相同的就不打印A字符串的某个元素

public static void main1(String[] args) {
    String str1="welcome to bit";
    String str2="come";
    char[] arr1=str1.toCharArray();
    char[] arr2=str2.toCharArray();
    for (int i = 0; i < arr1.length; i++) {
        int flg=1;
        for (int j = 0; j < arr2.length ; j++) {
              if(arr1[i]==arr2[j]){
                  flg=0;
              }
        }
        if(flg==1){
            System.out.print(arr1[i]);
        }
    }
}

2.list方法

 

先构建一个字符类顺序表

遍历字符串1.取下每个元素.如果第二个字符串没有.就添加到列表里,最后打印顺序表.

 

感觉这里跟sb方法如出一辙.

实现扑克牌

第一步定义牌

一张牌含有数字,和花色

再建立他的构造方法

 

 

在重写ToString

 

第二步,一组牌的实现

构建一个花色数组,后期构建牌,直接在数组拿,一组牌有四个花色,所以直接用final修饰

 

构建一副没有打乱顺序牌的方法

先建立一个牌的顺序表

 

每个花色有十三张牌,就构建两个for循环.建立一个牌,j下标就是对应数字,suit[i]就是对应花色

把每张牌放在顺序表中

第三步洗牌

 

这里要保证洗过的牌的位置不再被洗,

我们就从最后一个开始遍历,下次就往前进一位

因为random函数是在[0,x)范围.

我们让i下标的牌

与交换后的rand下标牌进行交换

我们就再建立一个交换牌方法

 

这里我们一定要注意,cards也要传进来,因为cards是成员变量定义在main函数中的

并且不能直接用拿数组的方式,因为这是一个表,

我们用顺序表的方法区拿.

第四步 揭牌

让每个人揭牌,五个回合,一次揭牌一张.一共三个人

 

所以我们就定义一个二维数组,每个下标存放的是每个人手牌的位置.

 

 

杨辉三角

 

先建立一个前几行的列表,把每一行的数组都放在一个列表里

初始化第一行

第一行就是1

并把第一行的数据放在ret中

构建循环,每一行每一行的构建,

每次进入一个循环都构建一个列表

定义每一行开头都是1

再次进入循环

因为除了每一行的开头和结尾是1/中间的都是上面的和上面的左边的元素相加得到

这里我们不能把开头和结尾加上,这样会造成数组越界

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> ret = new ArrayList<>();
        //第一行:
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        ret.add(list1);//才把第一行的数据存放到了ret当中
        for (int i=1;i<numRows;i++){
            List<Integer>list=new ArrayList<>();//构建每一行的列表
            list.add(1);//每一行开头都是1
            for (int j = 1; j < i; j++) {//如果i=3就代表已经是第四行了
                List<Integer> preRow=ret.get(i-1);
                int num=preRow.get(j-1)+preRow.get(j);
                list.add(num);
            }
            list.add(1);
            ret.add(list);
        }
        return ret;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值