• 01玩转数据结构_02_不要小瞧数组


    数组基础:

     1 package cn.zcb.demo01;
     2 
     3 public class Test {
     4     public static void main(String[] args) {
     5         //数组创建 和 初始化的两种方式
     6         //1
     7         int [] arr = new int[10];
     8         for (int i=0;i<arr.length ;i++){
     9             arr[i] = i;
    10         }
    11         //2
    12         int [] scores = new int[] {10,20,30,40};
    13 
    14         //下面是两种打印方式
    15         //1
    16         for (int i=0;i<scores.length;i++){
    17             System.out.println(scores[i]);
    18         }
    19         //2
    20         for (int score:scores){
    21             System.out.println(score);
    22         }
    23 
    24 
    25     }
    26 }
    27 /* 输出结果
    28 10
    29 20
    30 30
    31 40
    32 10
    33 20
    34 30
    35 40
    36 * */
    View Code

    索引的语义:

    所以可以有语义,也可以没有语义,

    有语义,例如0 代表学号,

    没有语义,例如0 只是代表第一个而已。

    数组最大的优点是:快速查询。所以,对于数组我们最好应用在“索引有语义”的情况。我们知道我们要查的是什么。

    但是并非所有的有语义的索引都适合用于数组!

    例如身份证号33333333333332442444444222!

    这个时候,也可以使用数组处理“索引没有语义”的情况。

    下面制作属于我们自己的数组类:

       

     1 package cn.zcb.demo01;
     2 
     3 public class MyArray {
     4     private int[] data; //数组
     5     private int size;  //数组实际大小,
     6     //容量不用写,可以由data.length()得知
     7 
     8     //满参构造函数
     9     public MyArray(int capacity){
    10         this.data  = new int[capacity];
    11         this.size = 0; //开始时 实际大小size =0
    12     }
    13     //空参构造器
    14     public MyArray(){
    15         this(10);  //如果是空参的话,调用有参构造器。默认是10
    16     }
    17 }
    基本写法!
     1 package cn.zcb.demo01;
     2 public class MyArray {
     3     private int[] data; //数组
     4     private int size;  //数组实际大小,
     5     //容量不用写,可以由data.length()得知
     6 
     7     //满参构造函数
     8     public MyArray(int capacity){
     9         this.data  = new int[capacity];
    10         this.size = 0; //开始时 实际大小size =0
    11     }
    12     //空参构造器
    13     public MyArray(){
    14         this(10);  //如果是空参的话,调用有参构造器。默认是10
    15     }
    16 
    17     //获取数组中的元素的个数
    18     public int getSize(){
    19         return this.size;
    20     }
    21 
    22     //获取数组的容量
    23     public int getCapacity(){
    24         return this.data.length;
    25     }
    26 
    27     //数组中是否为空
    28     public boolean isEmpty(){
    29         return this.size ==0;  
    30     }
    31 }
    View Code

    向我们自己的数组中添加元素(在数组末加):

     1 package cn.zcb.demo01;
     2 public class MyArray {
     3     private int[] data; //数组
     4     private int size;  //数组实际大小,
     5     //容量不用写,可以由data.length()得知
     6 
     7     //满参构造函数
     8     public MyArray(int capacity){
     9         this.data  = new int[capacity];
    10         this.size = 0; //开始时 实际大小size =0
    11     }
    12     //空参构造器
    13     public MyArray(){
    14         this(10);  //如果是空参的话,调用有参构造器。默认是10
    15     }
    16 
    17     //获取数组中的元素的个数
    18     public int getSize(){
    19         return this.size;
    20     }
    21 
    22     //获取数组的容量
    23     public int getCapacity(){
    24         return this.data.length;
    25     }
    26 
    27     //数组中是否为空
    28     public boolean isEmpty(){
    29         return this.size ==0;
    30     }
    31 
    32     //向 数组的末尾添加一个新元素
    33     public void addLast(int num){
    34         if(size == this.data.length){
    35             //此时开辟的空间已经满了
    36             //这里先抛出一个异常
    37             throw new IllegalArgumentException("addLast failed.数组已经满了");
    38         }
    39         this.data[size] = num;
    40         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
    41     }
    42 
    43 
    44 
    45 }
    View Code

    向我们自己的数组中添加元素(在数组指定位置添加):

     1 package cn.zcb.demo01;
     2 public class MyArray {
     3     private int[] data; //数组
     4     private int size;  //数组实际大小,
     5     //容量不用写,可以由data.length()得知
     6 
     7     //满参构造函数
     8     public MyArray(int capacity){
     9         this.data  = new int[capacity];
    10         this.size = 0; //开始时 实际大小size =0
    11     }
    12     //空参构造器
    13     public MyArray(){
    14         this(10);  //如果是空参的话,调用有参构造器。默认是10
    15     }
    16 
    17     //获取数组中的元素的个数
    18     public int getSize(){
    19         return this.size;
    20     }
    21 
    22     //获取数组的容量
    23     public int getCapacity(){
    24         return this.data.length;
    25     }
    26 
    27     //数组中是否为空
    28     public boolean isEmpty(){
    29         return this.size ==0;
    30     }
    31 
    32     //向 数组的末尾添加一个新元素
    33     public void addLast(int num){
    34         if(size == this.data.length){
    35             //此时开辟的空间已经满了
    36             //这里先抛出一个异常
    37             throw new IllegalArgumentException("addLast failed.数组已经满了");
    38         }
    39         this.data[size] = num;
    40         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
    41     }
    42 
    43     //向 指定数组位置添加一个新元素
    44     public void insert(int idx,int num){
    45         if(this.size == this.data.length){
    46             throw new IllegalArgumentException("数组已经放满了");
    47         }
    48         if(idx <0 || idx > this.size )
    49             throw new IllegalArgumentException("索引非法");
    50         
    51         for(int i=this.size-1;i >= idx;--i){
    52             this.data[i+1] = this.data[i];
    53         }
    54         this.data[idx] = num;
    55         //更新size
    56         this.size ++;
    57     }
    58 }
    version 01
     1 package cn.zcb.demo01;
     2 public class MyArray {
     3     private int[] data; //数组
     4     private int size;  //数组实际大小,
     5     //容量不用写,可以由data.length()得知
     6 
     7     //满参构造函数
     8     public MyArray(int capacity){
     9         this.data  = new int[capacity];
    10         this.size = 0; //开始时 实际大小size =0
    11     }
    12     //空参构造器
    13     public MyArray(){
    14         this(10);  //如果是空参的话,调用有参构造器。默认是10
    15     }
    16 
    17     //获取数组中的元素的个数
    18     public int getSize(){
    19         return this.size;
    20     }
    21 
    22     //获取数组的容量
    23     public int getCapacity(){
    24         return this.data.length;
    25     }
    26 
    27     //数组中是否为空
    28     public boolean isEmpty(){
    29         return this.size ==0;
    30     }
    31 
    32     //向 数组的末尾添加一个新元素
    33     public void addLast(int num){
    34         /*
    35         if(size == this.data.length){
    36             //此时开辟的空间已经满了
    37             //这里先抛出一个异常
    38             throw new IllegalArgumentException("addLast failed.数组已经满了");
    39         }
    40         this.data[size] = num;
    41         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
    42         */
    43         //此时其实可以直接复用 insert ()函数
    44         insert(this.size,num);
    45     }
    46 
    47     //向 指定数组位置添加一个新元素
    48     public void insert(int idx,int num){
    49         if(this.size == this.data.length){
    50             throw new IllegalArgumentException("数组已经放满了");
    51         }
    52         if(idx <0 || idx > this.size )
    53             throw new IllegalArgumentException("索引非法");
    54 
    55         for(int i=this.size-1;i >= idx;--i){
    56             this.data[i+1] = this.data[i];
    57         }
    58         this.data[idx] = num;
    59         //更新size
    60         this.size ++;
    61     }
    62 }
    给数组末尾添加元素函数 复用 指定位置添加函数

    而且,给数组头添加元素也可以直接复用 给指定位置添加元素的 函数!!!

     1 package cn.zcb.demo01;
     2 public class MyArray {
     3     private int[] data; //数组
     4     private int size;  //数组实际大小,
     5     //容量不用写,可以由data.length()得知
     6 
     7     //满参构造函数
     8     public MyArray(int capacity){
     9         this.data  = new int[capacity];
    10         this.size = 0; //开始时 实际大小size =0
    11     }
    12     //空参构造器
    13     public MyArray(){
    14         this(10);  //如果是空参的话,调用有参构造器。默认是10
    15     }
    16 
    17     //获取数组中的元素的个数
    18     public int getSize(){
    19         return this.size;
    20     }
    21 
    22     //获取数组的容量
    23     public int getCapacity(){
    24         return this.data.length;
    25     }
    26 
    27     //数组中是否为空
    28     public boolean isEmpty(){
    29         return this.size ==0;
    30     }
    31 
    32     //向 数组的末尾添加一个新元素
    33     public void addLast(int num){
    34         /*
    35         if(size == this.data.length){
    36             //此时开辟的空间已经满了
    37             //这里先抛出一个异常
    38             throw new IllegalArgumentException("addLast failed.数组已经满了");
    39         }
    40         this.data[size] = num;
    41         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
    42         */
    43         //此时其实可以直接复用 insert ()函数
    44         insert(this.size,num);
    45     }
    46     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
    47     public void addFirst(int num){
    48         insert(0,num); 
    49     }
    50     
    51     
    52     
    53     //向 指定数组位置添加一个新元素
    54     public void insert(int idx,int num){
    55         if(this.size == this.data.length){
    56             throw new IllegalArgumentException("数组已经放满了");
    57         }
    58         if(idx <0 || idx > this.size )
    59             throw new IllegalArgumentException("索引非法");
    60 
    61         for(int i=this.size-1;i >= idx;--i){
    62             this.data[i+1] = this.data[i];
    63         }
    64         this.data[idx] = num;
    65         //更新size
    66         this.size ++;
    67     }
    68 }
    View Code

     

    在我们自己的数组中查询和修改操作:

      1 package cn.zcb.demo01;
      2 public class MyArray {
      3     private int[] data; //数组
      4     private int size;  //数组实际大小,
      5     //容量不用写,可以由data.length()得知
      6 
      7     //满参构造函数
      8     public MyArray(int capacity){
      9         this.data  = new int[capacity];
     10         this.size = 0; //开始时 实际大小size =0
     11     }
     12     //空参构造器
     13     public MyArray(){
     14         this(10);  //如果是空参的话,调用有参构造器。默认是10
     15     }
     16 
     17     //获取数组中的元素的个数
     18     public int getSize(){
     19         return this.size;
     20     }
     21 
     22     //获取数组的容量
     23     public int getCapacity(){
     24         return this.data.length;
     25     }
     26 
     27     //数组中是否为空
     28     public boolean isEmpty(){
     29         return this.size ==0;
     30     }
     31 /////////////////////增////////////////////////////
     32     //向 数组的末尾添加一个新元素
     33     public void addLast(int num){
     34         /*
     35         if(size == this.data.length){
     36             //此时开辟的空间已经满了
     37             //这里先抛出一个异常
     38             throw new IllegalArgumentException("addLast failed.数组已经满了");
     39         }
     40         this.data[size] = num;
     41         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
     42         */
     43         //此时其实可以直接复用 insert ()函数
     44         insert(this.size,num);
     45     }
     46     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
     47     public void addFirst(int num){
     48         insert(0,num);
     49     }
     50 
     51     //向 指定数组位置添加一个新元素
     52     public void insert(int idx,int num){
     53         if(this.size == this.data.length){
     54             throw new IllegalArgumentException("数组已经放满了");
     55         }
     56         if(idx <0 || idx > this.size )
     57             throw new IllegalArgumentException("索引非法");
     58 
     59         for(int i=this.size-1;i >= idx;--i){
     60             this.data[i+1] = this.data[i];
     61         }
     62         this.data[idx] = num;
     63         //更新size
     64         this.size ++;
     65     }
     66 /////////////////////////////////////////////////////////////
     67     //修改索引为 idx 的元素为 num
     68     public void setByIndex(int idx,int num){
     69         if(idx <0 || idx > this.size)
     70             throw new IllegalArgumentException("idx 错误!");
     71 
     72         this.data[idx] = num;
     73     }
     74 
     75 
     76 /////////////////////////////////////////////////////////////
     77     //获取整个数组的概括
     78     //重写 toString()  当打印arr 时候,就会调用该方法!
     79     @Override
     80     public String toString(){
     81         StringBuilder res = new StringBuilder();
     82         res.append(String.format("Array:size = %d,capacity = %d 
    ",this.size,this.data.length));
     83         res.append('[');
     84         for (int i =0 ;i<this.size;i++){
     85             res.append(data[i]);
     86             if(i != this.size -1)
     87                 res.append(", ");
     88         }
     89         res.append(']');
     90         return res.toString();
     91     }
     92     //获取idx 索引位置的 元素
     93     public int getByIndex(int idx){
     94         if (idx < 0 || idx >this.size) {
     95             throw new IllegalArgumentException("索引传入错误!")
     96         }
     97         return this.data[idx];
     98     }
     99 
    100 
    101 
    102 }
    View Code

    在我们自己的数组中 包含,搜索,和删除  操作:

      1 package cn.zcb.demo01;
      2 public class MyArray {
      3     private int[] data; //数组
      4     private int size;  //数组实际大小,
      5     //容量不用写,可以由data.length()得知
      6 
      7     //满参构造函数
      8     public MyArray(int capacity){
      9         this.data  = new int[capacity];
     10         this.size = 0; //开始时 实际大小size =0
     11     }
     12     //空参构造器
     13     public MyArray(){
     14         this(10);  //如果是空参的话,调用有参构造器。默认是10
     15     }
     16 
     17     //获取数组中的元素的个数
     18     public int getSize(){
     19         return this.size;
     20     }
     21 
     22     //获取数组的容量
     23     public int getCapacity(){
     24         return this.data.length;
     25     }
     26 
     27     //数组中是否为空
     28     public boolean isEmpty(){
     29         return this.size ==0;
     30     }
     31 /////////////////////增////////////////////////////
     32     //向 数组的末尾添加一个新元素
     33     public void addLast(int num){
     34         /*
     35         if(size == this.data.length){
     36             //此时开辟的空间已经满了
     37             //这里先抛出一个异常
     38             throw new IllegalArgumentException("addLast failed.数组已经满了");
     39         }
     40         this.data[size] = num;
     41         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
     42         */
     43         //此时其实可以直接复用 insert ()函数
     44         insert(this.size,num);
     45     }
     46     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
     47     public void addFirst(int num){
     48         insert(0,num);
     49     }
     50 
     51     //向 指定数组位置添加一个新元素
     52     public void insert(int idx,int num){
     53         if(this.size == this.data.length){
     54             throw new IllegalArgumentException("数组已经放满了");
     55         }
     56         if(idx <0 || idx > this.size )
     57             throw new IllegalArgumentException("索引非法");
     58 
     59         for(int i=this.size-1;i >= idx;--i){
     60             this.data[i+1] = this.data[i];
     61         }
     62         this.data[idx] = num;
     63         //更新size
     64         this.size ++;
     65     }
     66 
     67 /////////////////////////////////////////////////////////////
     68     //删除第一个
     69     public int removeFirst(){
     70         return remove(0);  //删除并将之返回出去
     71     }
     72 
     73     //删除最后一个
     74     public int removeLast(){
     75         return remove(this.size-1);
     76     }
     77 
     78     //删除指定位置  的元素
     79     public int remove(int idx){  //返回 删除的元素
     80         if(idx < 0 || idx > this.size -1)
     81             throw new IllegalArgumentException("idx错误!");
     82         int temp = this.data[idx];
     83         for (int i =idx;i<this.size - 1;i++){
     84             this.data[i] = this.data[i+1];
     85         }
     86 
     87         this.size -- ;
     88         return temp;
     89     }
     90 
     91     //删除 某个元素 不根据其位置  //它之所以返回void 是因为调用着已经知道的element ,所以没必要再返回出来了。
     92     public void removeElement(int element){
     93         //首先要 寻找是否有 element
     94         int idx = find(element);
     95         if(idx == -1){
     96             throw new IllegalArgumentException("没有该元素");
     97         }else{
     98             remove(idx);
     99         }
    100     }     
    101 
    102 /////////////////////////////////////////////////////////////
    103     //修改索引为 idx 的元素为 num
    104     public void setByIndex(int idx,int num){
    105         if(idx <0 || idx > this.size)
    106             throw new IllegalArgumentException("idx 错误!");
    107 
    108         this.data[idx] = num;
    109     }
    110 
    111 
    112 /////////////////////////////////////////////////////////////
    113     //获取整个数组的概括
    114     //重写 toString()  当打印arr 时候,就会调用该方法!
    115     @Override
    116     public String toString(){
    117         StringBuilder res = new StringBuilder();
    118         res.append(String.format("Array:size = %d,capacity = %d 
    ",this.size,this.data.length));
    119         res.append('[');
    120         for (int i =0 ;i<this.size;i++){
    121             res.append(data[i]);
    122             if(i != this.size -1)
    123                 res.append(", ");
    124         }
    125         res.append(']');
    126         return res.toString();
    127     }
    128     //获取idx 索引位置的 元素
    129     public int getByIndex(int idx){
    130         if (idx < 0 || idx >this.size) {
    131             throw new IllegalArgumentException("索引传入错误!");
    132         }
    133         return this.data[idx];
    134     }
    135 
    136 //////////////////////包含///////////////////////////////////////
    137     public boolean contains(int num){
    138         for (int i=0;i<this.size;i++){
    139             if(this.data[i] == num){
    140                 return true;
    141             }
    142         }
    143         return false;
    144     }
    145 //////////////////////寻找////////////////////////////////////
    146     public int find(int num){
    147         //寻找数组中是否有 num  ,如果有返回其索引,反之 返回-1
    148         for (int i =0;i<this.size;i++){
    149             if(this.data[i] == num){
    150                 return i;
    151             }
    152         }
    153         return -1;
    154     }
    155 
    156 
    157 }
    View Code

    到目前为止,我们自己的数组类已经初具雏形了!

    调试代码:

     1 package cn.zcb.demo01;
     2 
     3 public class Test {
     4     public static void main(String[] args) {
     5         MyArray arr = new MyArray(10);
     6 
     7         //数组的容量
     8         System.out.println(arr.getCapacity());
     9 
    10         //目前数组的大小
    11         System.out.println(arr.getSize());
    12 
    13         //在数组末尾加一个数
    14         arr.addLast(18);
    15 
    16         //在 0 索引加入 7
    17         arr.insert(0,7);
    18 
    19         System.out.println(arr.getSize());
    20 
    21         //查看数组内容  会调用重写之后的toString()
    22         System.out.println(arr);
    23 
    24         //在数组的头部 加-10
    25         arr.addFirst(-10);
    26         System.out.println(arr);
    27 
    28         System.out.println(arr.contains(7));
    29         System.out.println(arr.contains(101));
    30 
    31         //删除指定位置的元素
    32         int res =  arr.remove(0); //删除索引为0 的元素
    33         System.out.println(res);
    34         System.out.println(arr); //再次打印 arr
    35 
    36 
    37     }
    38 }
    View Code

    改善我们自己的数组之---使用泛型:

     目前我们自己写的数组类最大的问题就是它只能存放int 数据类型,这肯定是不行的。 

      1 package cn.zcb.demo01;
      2 
      3 public class MyArray<T> {
      4     private T[] data; //数组
      5     private int size;  //数组实际大小,
      6     //容量不用写,可以由data.length()得知
      7 
      8     //满参构造函数
      9     public MyArray(int capacity){
     10 //        this.data  = new int[capacity];
     11 //        this.data  = new T[capacity];  //不支持这样
     12         this.data =  (T[]) new Object[capacity];  //先new 出个 Object[]  类的,然后转为 T[]
     13         this.size = 0; //开始时 实际大小size =0
     14     }
     15     //空参构造器
     16     public MyArray(){
     17         this(10);  //如果是空参的话,调用有参构造器。默认是10
     18     }
     19 
     20     //获取数组中的元素的个数
     21     public int getSize(){
     22         return this.size;
     23     }
     24 
     25     //获取数组的容量
     26     public int getCapacity(){
     27         return this.data.length;
     28     }
     29 
     30     //数组中是否为空
     31     public boolean isEmpty(){
     32         return this.size ==0;
     33     }
     34 /////////////////////增////////////////////////////
     35     //向 数组的末尾添加一个新元素
     36     public void addLast(T num){
     37         /*
     38         if(size == this.data.length){
     39             //此时开辟的空间已经满了
     40             //这里先抛出一个异常
     41             throw new IllegalArgumentException("addLast failed.数组已经满了");
     42         }
     43         this.data[size] = num;
     44         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
     45         */
     46         //此时其实可以直接复用 insert ()函数
     47         insert(this.size,num);
     48     }
     49     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
     50     public void addFirst(T num){
     51         insert(0,num);
     52     }
     53 
     54     //向 指定数组位置添加一个新元素
     55     public void insert(int idx,T num){
     56         if(this.size == this.data.length){
     57             throw new IllegalArgumentException("数组已经放满了");
     58         }
     59         if(idx <0 || idx > this.size )
     60             throw new IllegalArgumentException("索引非法");
     61 
     62         for(int i=this.size-1;i >= idx;--i){
     63             this.data[i+1] = this.data[i];
     64         }
     65         this.data[idx] = num;
     66         //更新size
     67         this.size ++;
     68     }
     69 
     70 /////////////////////////////////////////////////////////////
     71     //删除第一个
     72     public T removeFirst(){
     73         return remove(0);  //删除并将之返回出去
     74     }
     75 
     76     //删除最后一个
     77     public T removeLast(){
     78         return remove(this.size-1);
     79     }
     80 
     81     //删除指定位置  的元素
     82     public T remove(int idx){  //返回 删除的元素
     83         if(idx < 0 || idx > this.size -1)
     84             throw new IllegalArgumentException("idx错误!");
     85         T temp = this.data[idx];
     86         for (int i =idx;i<this.size - 1;i++){
     87             this.data[i] = this.data[i+1];
     88         }
     89 
     90         this.size -- ;
     91         return temp;
     92     }
     93 
     94     //删除 某个元素 不根据其位置  //它之所以返回void 是因为调用着已经知道的element ,所以没必要再返回出来了。
     95     public void removeElement(T element){
     96         //首先要 寻找是否有 element
     97         int idx = find(element);
     98         if(idx == -1){
     99             throw new IllegalArgumentException("没有该元素");
    100         }else{
    101             remove(idx);
    102         }
    103     }
    104 
    105 /////////////////////////////////////////////////////////////
    106     //修改索引为 idx 的元素为 num
    107     public void setByIndex(int idx,T num){
    108         if(idx <0 || idx > this.size)
    109             throw new IllegalArgumentException("idx 错误!");
    110 
    111         this.data[idx] = num;
    112     }
    113 
    114 
    115 /////////////////////////////////////////////////////////////
    116     //获取整个数组的概括
    117     //重写 toString()  当打印arr 时候,就会调用该方法!
    118     @Override
    119     public String toString(){
    120         StringBuilder res = new StringBuilder();
    121         res.append(String.format("Array:size = %d,capacity = %d 
    ",this.size,this.data.length));
    122         res.append('[');
    123         for (int i =0 ;i<this.size;i++){
    124             res.append(data[i]);
    125             if(i != this.size -1)
    126                 res.append(", ");
    127         }
    128         res.append(']');
    129         return res.toString();
    130     }
    131     //获取idx 索引位置的 元素
    132     public T getByIndex(int idx){
    133         if (idx < 0 || idx >this.size) {
    134             throw new IllegalArgumentException("索引传入错误!");
    135         }
    136         return this.data[idx];
    137     }
    138 
    139 //////////////////////包含///////////////////////////////////////
    140     public boolean contains(T num){
    141         for (int i=0;i<this.size;i++){
    142             if(this.data[i] == num){
    143                 return true;
    144             }
    145         }
    146         return false;
    147     }
    148 //////////////////////寻找////////////////////////////////////
    149     public int find(T num){
    150         //寻找数组中是否有 num  ,如果有返回其索引,反之 返回-1
    151         for (int i =0;i<this.size;i++){
    152             if(this.data[i] == num){
    153                 return i;
    154             }
    155         }
    156         return -1;
    157     }
    158 
    159 }
    MyArray.java
     1 package cn.zcb.demo01;
     2 
     3 public class Person {
     4 
     5     private String name;
     6     private int age;
     7 
     8     public Person(String name,int age){
     9         this.name = name;
    10         this.age = age;
    11     }
    12     public Person(){
    13         this("张三",18);  //默认赋值 张三 18
    14     }
    15 
    16 
    17 }
    Person.java
     1 package cn.zcb.demo01;
     2 
     3 public class Test {
     4 
     5 
     6     public static void main(String[] args) {
     7         MyArray<Integer> arrInt = new MyArray<Integer>(11);
     8         arrInt.addLast(10);
     9         arrInt.addLast(11);
    10         arrInt.addLast(12);
    11         System.out.println(arrInt);
    12 
    13         MyArray<Character> arrChar = new MyArray<Character>(11);
    14         arrChar.addLast('1');
    15         arrChar.addLast('a');
    16         arrChar.addLast('b');
    17         arrChar.addLast('c');
    18         System.out.println(arrChar);
    19 
    20         //自定义类型  Person
    21         Person p1 = new Person("tom",18);
    22         Person p2 = new Person("egon",20);
    23         Person p3 = new Person("alex",30);
    24 
    25         MyArray<Person> arrPerson = new MyArray<>();  // <>  中的类型是可以省略的。
    26         arrPerson.addLast(p1);
    27         arrPerson.addLast(p2);
    28         arrPerson.addLast(p3);
    29         System.out.println(arrPerson);
    30     }
    31 }
    32 /* 输出结果
    33 Array:size = 3,capacity = 11
    34 [10, 11, 12]
    35 Array:size = 4,capacity = 11
    36 [1, a, b, c]
    37 Array:size = 3,capacity = 10
    38 [cn.zcb.demo01.Person@17a7cec2, cn.zcb.demo01.Person@65b3120a, cn.zcb.demo01.Person@6f539caf]
    39 * */
    Test.java

    改善我们自己的数组之---动态数组:

    此时不够用了,

    以上整个过程是封装在一个函数中。

    原本的四个的数组,由于没有人指向它了,所以Java的垃圾回收机制会将它回收。

    上面其实有个缺点是:如果一个数组太大的话,每一个都遍历复制到一个新的地方,这确实是在性能上有所缺陷。这个问题将在下面讨论。

    而且,删除的时候,也是用的这个思路。这样就可以实现动态数组了。

      1 package cn.zcb.demo01;
      2 
      3 public class MyArray<T> {
      4     private T[] data; //数组
      5     private int size;  //数组实际大小,
      6     //容量不用写,可以由data.length()得知
      7 
      8     //满参构造函数
      9     public MyArray(int capacity){
     10 //        this.data  = new int[capacity];
     11 //        this.data  = new T[capacity];  //不支持这样
     12         this.data =  (T[]) new Object[capacity];  //先new 出个 Object[]  类的,然后转为 T[]
     13         this.size = 0; //开始时 实际大小size =0
     14     }
     15     //空参构造器
     16     public MyArray(){
     17         this(10);  //如果是空参的话,调用有参构造器。默认是10
     18     }
     19 
     20     //获取数组中的元素的个数
     21     public int getSize(){
     22         return this.size;
     23     }
     24 
     25     //获取数组的容量
     26     public int getCapacity(){
     27         return this.data.length;
     28     }
     29 
     30     //数组中是否为空
     31     public boolean isEmpty(){
     32         return this.size ==0;
     33     }
     34 /////////////////////增////////////////////////////
     35     //向 数组的末尾添加一个新元素
     36     public void addLast(T num){
     37         /*
     38         if(size == this.data.length){
     39             //此时开辟的空间已经满了
     40             //这里先抛出一个异常
     41             throw new IllegalArgumentException("addLast failed.数组已经满了");
     42         }
     43         this.data[size] = num;
     44         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
     45         */
     46         //此时其实可以直接复用 insert ()函数
     47         insert(this.size,num);
     48     }
     49     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
     50     public void addFirst(T num){
     51         insert(0,num);
     52     }
     53 
     54     //向 指定数组位置添加一个新元素
     55     public void insert(int idx,T num){
     56         if(this.size == this.data.length){
     57 //            throw new IllegalArgumentException("数组已经放满了");
     58             /*此时对其扩容*/
     59             resize(2*this.data.length);
     60 
     61 
     62         }
     63         if(idx <0 || idx > this.size )
     64             throw new IllegalArgumentException("索引非法");
     65 
     66         for(int i=this.size-1;i >= idx;--i){
     67             this.data[i+1] = this.data[i];
     68         }
     69         this.data[idx] = num;
     70         //更新size
     71         this.size ++;
     72     }
     73 
     74 /////////////////////////////////////////////////////////////
     75     //删除第一个
     76     public T removeFirst(){
     77         return remove(0);  //删除并将之返回出去
     78     }
     79 
     80     //删除最后一个
     81     public T removeLast(){
     82         return remove(this.size-1);
     83     }
     84 
     85     //删除指定位置  的元素
     86     public T remove(int idx){  //返回 删除的元素
     87         if(idx < 0 || idx > this.size -1)
     88             throw new IllegalArgumentException("idx错误!");
     89         T temp = this.data[idx];
     90         for (int i =idx;i<this.size - 1;i++){
     91             this.data[i] = this.data[i+1];
     92         }
     93         this.size -- ;
     94 
     95         //动态减少   当数组中的元素少于空间的一半的时候,就缩减空间。
     96         if(this.size == this.data.length / 2){
     97             System.out.println("size = "+this.size);
     98 
     99             resize(this.data.length/2);
    100         }
    101         return temp;
    102     }
    103 
    104     //删除 某个元素 不根据其位置  //它之所以返回void 是因为调用着已经知道的element ,所以没必要再返回出来了。
    105     public void removeElement(T element){
    106         //首先要 寻找是否有 element
    107         int idx = find(element);
    108         if(idx == -1){
    109             throw new IllegalArgumentException("没有该元素");
    110         }else{
    111             remove(idx);
    112         }
    113     }
    114 
    115 /////////////////////////////////////////////////////////////
    116     //修改索引为 idx 的元素为 num
    117     public void setByIndex(int idx,T num){
    118         if(idx <0 || idx > this.size)
    119             throw new IllegalArgumentException("idx 错误!");
    120 
    121         this.data[idx] = num;
    122     }
    123 
    124 
    125 /////////////////////////////////////////////////////////////
    126     //获取整个数组的概括
    127     //重写 toString()  当打印arr 时候,就会调用该方法!
    128     @Override
    129     public String toString(){
    130         StringBuilder res = new StringBuilder();
    131         res.append(String.format("Array:size = %d,capacity = %d 
    ",this.size,this.data.length));
    132         res.append('[');
    133         for (int i =0 ;i<this.size;i++){
    134             res.append(data[i]);
    135             if(i != this.size -1)
    136                 res.append(", ");
    137         }
    138         res.append(']');
    139         return res.toString();
    140     }
    141     //获取idx 索引位置的 元素
    142     public T getByIndex(int idx){
    143         if (idx < 0 || idx >this.size) {
    144             throw new IllegalArgumentException("索引传入错误!");
    145         }
    146         return this.data[idx];
    147     }
    148 
    149 //////////////////////包含///////////////////////////////////////
    150     public boolean contains(T num){
    151         for (int i=0;i<this.size;i++){
    152             if(this.data[i] == num){
    153                 return true;
    154             }
    155         }
    156         return false;
    157     }
    158 //////////////////////寻找////////////////////////////////////
    159     public int find(T num){
    160         //寻找数组中是否有 num  ,如果有返回其索引,反之 返回-1
    161         for (int i =0;i<this.size;i++){
    162             if(this.data[i] == num){
    163                 return i;
    164             }
    165         }
    166         return -1;
    167     }
    168 //////////////////////实现动态数组  resize()////////////////////////////////////
    169     private void resize(int new_capacity){  //之所以  用 private 是不让用户调用, 数组如果空间不足会自己扩展的。
    170         T[] new_data =(T[]) new Object[new_capacity];
    171 
    172         for (int i =0;i<this.size;i++){
    173             new_data[i] = this.data[i];
    174         }
    175         //
    176         this.data = new_data;  //此时新数组的size 不变 , 新数组的length 也不用变
    177     }
    178 }
    实现动态 增减功能的数组!!!
     1 package cn.zcb.demo01;
     2 /* 动态增加测试
     3 public class Test {
     4 
     5 
     6     public static void main(String[] args) {
     7         MyArray<Integer> arrInt = new MyArray<Integer>(4);
     8         arrInt.addLast(10);
     9         arrInt.addLast(11);
    10         arrInt.addLast(12);
    11         arrInt.addLast(13);
    12         System.out.println(arrInt);
    13         arrInt.addLast(14);
    14         System.out.println(arrInt);
    15     }
    16 }
    17 输出结果
    18 Array:size = 4,capacity = 4
    19 [10, 11, 12, 13]
    20 Array:size = 5,capacity = 8
    21 [10, 11, 12, 13, 14]
    22 * */
    23 
    24 //动态减少测试  n =4 时的减少
    25 /*
    26 public class Test {
    27     public static void main(String[] args) {
    28         MyArray<Integer> arrInt = new MyArray<Integer>(4);
    29         arrInt.addLast(10);
    30         arrInt.addLast(11);
    31         arrInt.addLast(12);
    32         arrInt.addLast(13);
    33         System.out.println(arrInt);
    34         arrInt.remove(0); //删除
    35         arrInt.remove(0);
    36         System.out.println(arrInt);
    37     }
    38 }
    39 
    40 输出结果
    41 Array:size = 4,capacity = 4
    42 [10, 11, 12, 13]
    43 size = 2
    44 Array:size = 2,capacity = 2
    45 [12, 13]
    46 * */
    47 
    48 
    49 
    50 //动态减少测试  n =5 时的减少
    51 
    52 public class Test {
    53     public static void main(String[] args) {
    54         MyArray<Integer> arrInt = new MyArray<Integer>(5);
    55         arrInt.addLast(10);
    56         arrInt.addLast(11);
    57         arrInt.addLast(12);
    58         arrInt.addLast(13);
    59         arrInt.addLast(14);
    60         System.out.println(arrInt);
    61         arrInt.remove(0); //删除
    62         arrInt.remove(0);
    63         arrInt.remove(0);
    64         System.out.println(arrInt);
    65     }
    66 }
    67 /* 输出结果
    68 Array:size = 5,capacity = 5
    69 [10, 11, 12, 13, 14]
    70 size = 2
    71 Array:size = 2,capacity = 2
    72 [13, 14]
    73 * */
    相应的调试代码!!!

    改善我们自己的数组之---简单的时间复杂度分析:

    其实c1 和  c2 是很难精确得知的,它在不同语言不同平台都可能有差别!

    时间复杂度为O(n) 的 一定比 时间复杂度为O(n^2) 的优吗?
    不一定,例如上述的第二个和第三个,当n =10 时,第二个的T= 30000 第三个的T= 100

    因此,针对任意一个输入,并不是O(n) 的算法,一定优于O(n^2) 的(此时O(n) 的系数起到大的作用!) 。

    但,大O ,描述的其实是当n 趋近于无穷的时候的情况。  

     

    resize 的时间复杂度分析:

    虽然上述分析没有错误,但是,我们忽略了一个问题,就是并不是每次我们都需要进行resize操作

    可以如下分析:

    但是同时进行addLast 和  removeLast 时候就出问题了:

    这个问题叫做复杂度震荡

    是数组长度的1/4 的时候,再缩容,缩小1/2  。

    这样就可以有效的防止了 复杂度震荡的问题了。

    所以,在算法中有时“懒”一点反而可以提高代码的整体性能!!!

    改善之后的代码:主要在remove()中:

      1 package cn.zcb.demo01;
      2 
      3 public class MyArray<T> {
      4     private T[] data; //数组
      5     private int size;  //数组实际大小,
      6     //容量不用写,可以由data.length()得知
      7 
      8     //满参构造函数
      9     public MyArray(int capacity){
     10 //        this.data  = new int[capacity];
     11 //        this.data  = new T[capacity];  //不支持这样
     12         this.data =  (T[]) new Object[capacity];  //先new 出个 Object[]  类的,然后转为 T[]
     13         this.size = 0; //开始时 实际大小size =0
     14     }
     15     //空参构造器
     16     public MyArray(){
     17         this(10);  //如果是空参的话,调用有参构造器。默认是10
     18     }
     19 
     20     //获取数组中的元素的个数
     21     public int getSize(){
     22         return this.size;
     23     }
     24 
     25     //获取数组的容量
     26     public int getCapacity(){
     27         return this.data.length;
     28     }
     29 
     30     //数组中是否为空
     31     public boolean isEmpty(){
     32         return this.size ==0;
     33     }
     34 /////////////////////增////////////////////////////
     35     //向 数组的末尾添加一个新元素
     36     public void addLast(T num){
     37         /*
     38         if(size == this.data.length){
     39             //此时开辟的空间已经满了
     40             //这里先抛出一个异常
     41             throw new IllegalArgumentException("addLast failed.数组已经满了");
     42         }
     43         this.data[size] = num;
     44         size ++;  //要维持数组  指针。 size 是当前数组中的个数。
     45         */
     46         //此时其实可以直接复用 insert ()函数
     47         insert(this.size,num);
     48     }
     49     // 向数组头添加元素 (直接复用  向指定位置添加元素的函数 )
     50     public void addFirst(T num){
     51         insert(0,num);
     52     }
     53 
     54     //向 指定数组位置添加一个新元素
     55     public void insert(int idx,T num){
     56         if(this.size == this.data.length){
     57 //            throw new IllegalArgumentException("数组已经放满了");
     58             /*此时对其扩容*/
     59             resize(2*this.data.length);
     60 
     61 
     62         }
     63         if(idx <0 || idx > this.size )
     64             throw new IllegalArgumentException("索引非法");
     65 
     66         for(int i=this.size-1;i >= idx;--i){
     67             this.data[i+1] = this.data[i];
     68         }
     69         this.data[idx] = num;
     70         //更新size
     71         this.size ++;
     72     }
     73 
     74 /////////////////////////////////////////////////////////////
     75     //删除第一个
     76     public T removeFirst(){
     77         return remove(0);  //删除并将之返回出去
     78     }
     79 
     80     //删除最后一个
     81     public T removeLast(){
     82         return remove(this.size-1);
     83     }
     84 
     85     //删除指定位置  的元素
     86     public T remove(int idx){  //返回 删除的元素
     87         if(idx < 0 || idx > this.size -1)
     88             throw new IllegalArgumentException("idx错误!");
     89         T temp = this.data[idx];
     90         for (int i =idx;i<this.size - 1;i++){
     91             this.data[i] = this.data[i+1];
     92         }
     93         this.size -- ;
     94 
     95         //动态减少   当数组中的元素少于空间的四分之一的时候,缩减空间为原来的一半(这样可以有效的防止 复杂度震荡问题)。
     96         if(this.size == this.data.length / 4 && this.data.length/2 != 0 ){  //第二个条件是防止 length =1 的时候
     97             resize(this.data.length/2);
     98         }
     99         return temp;
    100     }
    101 
    102     //删除 某个元素 不根据其位置  //它之所以返回void 是因为调用着已经知道的element ,所以没必要再返回出来了。
    103     public void removeElement(T element){
    104         //首先要 寻找是否有 element
    105         int idx = find(element);
    106         if(idx == -1){
    107             throw new IllegalArgumentException("没有该元素");
    108         }else{
    109             remove(idx);
    110         }
    111     }
    112 
    113 /////////////////////////////////////////////////////////////
    114     //修改索引为 idx 的元素为 num
    115     public void setByIndex(int idx,T num){
    116         if(idx <0 || idx > this.size)
    117             throw new IllegalArgumentException("idx 错误!");
    118 
    119         this.data[idx] = num;
    120     }
    121 
    122 
    123 /////////////////////////////////////////////////////////////
    124     //获取整个数组的概括
    125     //重写 toString()  当打印arr 时候,就会调用该方法!
    126     @Override
    127     public String toString(){
    128         StringBuilder res = new StringBuilder();
    129         res.append(String.format("Array:size = %d,capacity = %d 
    ",this.size,this.data.length));
    130         res.append('[');
    131         for (int i =0 ;i<this.size;i++){
    132             res.append(data[i]);
    133             if(i != this.size -1)
    134                 res.append(", ");
    135         }
    136         res.append(']');
    137         return res.toString();
    138     }
    139     //获取idx 索引位置的 元素
    140     public T getByIndex(int idx){
    141         if (idx < 0 || idx >this.size) {
    142             throw new IllegalArgumentException("索引传入错误!");
    143         }
    144         return this.data[idx];
    145     }
    146 
    147 //////////////////////包含///////////////////////////////////////
    148     public boolean contains(T num){
    149         for (int i=0;i<this.size;i++){
    150             if(this.data[i] == num){
    151                 return true;
    152             }
    153         }
    154         return false;
    155     }
    156 //////////////////////寻找////////////////////////////////////
    157     public int find(T num){
    158         //寻找数组中是否有 num  ,如果有返回其索引,反之 返回-1
    159         for (int i =0;i<this.size;i++){
    160             if(this.data[i] == num){
    161                 return i;
    162             }
    163         }
    164         return -1;
    165     }
    166 //////////////////////实现动态数组  resize()////////////////////////////////////
    167     private void resize(int new_capacity){  //之所以  用 private 是不让用户调用, 数组如果空间不足会自己扩展的。
    168         T[] new_data =(T[]) new Object[new_capacity];
    169 
    170         for (int i =0;i<this.size;i++){
    171             new_data[i] = this.data[i];
    172         }
    173         //
    174         this.data = new_data;  //此时新数组的size 不变 , 新数组的length 也不用变
    175     }
    176 }
    View Code
  • 相关阅读:
    SSH 远程执行任务
    C# 创建压缩文件
    迁移 SQL Server 到 Azure SQL 实战
    在 Azure 上部署 Asp.NET Core Web App
    linux kill 命令
    VS 远程调试 Azure Web App
    Azure 基础:自定义 Table storage 查询条件
    NSOperation的使用细节 [2]
    NSOperation的使用细节 [1]
    [翻译] SSKeychain
  • 原文地址:https://www.cnblogs.com/zach0812/p/11815611.html
Copyright © 2020-2023  润新知