返回顶部

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 \n",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 \n",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 \n",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 \n",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 \n",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

 

posted @ 2019-11-07 21:03  Zcb0812  阅读(142)  评论(0编辑  收藏  举报