Java language using a dynamic array (Detailed) (data structure) using a dynamic array java language (Detailed) (data structure)

Java language using a dynamic array (Detailed) (data structure)

 

 

Ado, on the code

1. From the beginning of the class name (I'm so sweet, give yourself a point like this)

public class Array<E>

First class needs with an array of generic, This much said. Note that in java, the array can hold only a single type.


2. The member variables

private int size; // number of elements in the array 
private E [] data; // array declaration


Insert a digression:
about the size and index, so when I was beginning to learn an array of trouble, first of all indexed arrays are zero, while the index size is an element of the group
number, assuming that the array has three elements, then size = 3, and the index was 0,1. They are poor one, and let the magic of the design every time I write boundary conditions at the time of the cycle,
always convert it.
For example, traversing all the elements of the array

for (int i = 0; i < size; i++) { }


My mentality is this:
  First of all, the first step would like, starting from 0, the index position of the last element to the end, then the index of the last element is supposed to come in the for loop, then i should
be less than the last the next index position of the element, then the index of the last element in the next who is it for, oh, size of magnitude larger than the index, it should be the size,
so should i <size;
if each write for when the cycle boundaries, we must think about, wasteful consumption of mental Afghanistan. Is it just me stupid.
Finally, my way is converted into map in her mind. Every time you use direct mind emerges out of this figure.

Nature of learning is to simplify complex things.

 


3. The method of construction
a user-specified initial capacity of the array
A user does not specify the initial capacity of the array

Copy the code
the Array public (int Capacity) { 
Data = (E []) new new Object [Capacity]; 
size = 0; 
} 

public the Array () { 
the this (10); // constructor calls another, and a default capacity is 10 
}
Copy the code


4. home of the necessary basic

Copy the code
// obtain the array element number of the 
public int getSize () { 
return size; 
} 
// get the array length 
public int getCapacity () { 
return data.length; 
} 
// if the array is empty obtained 
public Boolean isEmpty () { 
return size = = 0; 
}
Copy the code

 

5. Add Method

Nature add to the array is: from the back to the specified index, each element moves back a grid, to make room for a new place. 
Focus: From back to front
Copy the code
// the specified position of the element added to the array, index for the specified index, e is the value of the added 
public void the Add (int index, E E) { 
// index position it can not be inserted blind, the index is negative, or jump grid interpolation, not. 
IF (index <0 || index> size) { 
the throw new new an IllegalArgumentException ( "the Add IS Fail, the require index <0 || index> size"); 
} 
// if the array is full capacity when calling expansion method, where it expanded to twice the current length of the array. 
IF (data.length == size) { 
this.resize (data.length * 2); 
} for (int size = I -. 1; I> = index; i--) { 
Data [I +. 1] = Data [ I]; 
} 
// into the pit of the new 
Data [index] = E; 
// maintenance size 
size ++; 

}
Copy the code

 

Copy the code
// add elements to the array of the first 
public void the addFirst (E E) { 
// add a method of directly multiplexing spend 
this.add (0, E); 
} 
// add elements to the array a last 
public void addLast (E E) { 
// Similarly 
this.add (size, E); 
}
Copy the code

 


6. Delete method (my personal divided into two types according to the index to delete a delete based on the value)

Nature delete: and add contrast, an index from the next position to be deleted, to the end of the last element index position, followed by possession of a pit forward. 
Important: when traversing from front to back
Copy the code
// delete elements according to the index return an element to delete 
public E Remove (int index) { 
IF (index <0 || index> = size) { 
the throw new new an IllegalArgumentException ( "Remove IS Fail, the require index <0 || index> size = "); 
} 
// first element to remove save up, or so will give cover. 
Data value = E [index]; 
for (int I = index +. 1; I <size; I ++) { 
Data [-I. 1] = Data [I]; 
} 
// maintenance size 
size -; 
// here Why set to null, because the generic reasons, are passed in class objects stored in the array is a reference address, cited constantly open, then the garbage collector can not reclaim. 
Data [size] = null; 
// where volume reduction, when the number of array elements is equal to a quarter the length of the array, is reduced in volume 
if (size == data.length / 4 && data.length / 2 = 0! ) { // volume reduction of one-half the length of the array this.resize (data.length / 2); } return value; }
Copy the code

The question is, why not just be one-half volume reduction of it? But a quarter of it?
Here it comes to the complexity of the concussion issue, a more extreme case: for example, the capacity of an array of 10, at which point the array is full, this time to come in elements and array expansion, then you have added elements of the array at this time for the case where a capacity of 20, internal element 11. At this point I would delete an element of the array, then delete, number of array elements becomes 10, exactly one-half the length of the array, then the automatic volume reduction, and so on, the operation is repeated, each expansion contraction receiving the time complexity is O (n), is applied here so lazy solution is to wait until the number of array elements is one-quarter the length of the array, further volume reduction, this problem is avoided.

 

Copy the code
// delete an element based on the value 
public void removeByValue (E E) { 
// find the multiplexing method according to the value of the element, returns the index (this method below) 
int index = this.getByElement (E); 
IF (index =! -1) { 
// multiplexing method according to the index deleted 
this.remove (index); 
} 
} 
// remove the first element of a 
public removeFirst E () { 
return this.remove (0); 
} 
// remove the last element 
E removeLast public () { 
return this.remove (size -. 1); 
}
Copy the code

 


7. The lookup method (again divided into two types according to the index A according to the value )

Copy the code
// the index a lookup array element, the return value 
public the getByIndex E (int index) { 

IF (index <0 || index> = size) { 
the throw new new an IllegalArgumentException ( "GET IS Fail, the require index <0 || index> size = "); 
} 

return Data [index]; 
}
Copy the code

 

Copy the code
// The value lookup an element array, returns the index of 
public int getByElement (E E) { 
// nature: traverse the array are aligned 
for (int I = 0; I <size; I ++) { 
IF (Data [I]. the equals (E)) { 
return I; 
} 
} 
return -1; 
}
Copy the code

 

Copy the code
// whether the element contains 
public Boolean the contains (E E) { 
// nature: traverse the array are aligned 
for (int I = 0; I <size; I ++) { 
IF (Data [I] .equals (E)) { 
to true return; 
} 
} 
return to false; 
}
Copy the code

 


8. The method of modification

Copy the code
//修改数组某个元素
public void set (int index, E e) {

if (index < 0 || index >= size) {
throw new IllegalArgumentException("set is fail, require index < 0 || index >= size");
}

data[index] = e;
}
Copy the code

 


9. Capacity Expansion with
expansion of nature: that is, to open up a new array, copy the contents of the old array past

Copy the code
Private void a resize (int newCatacity) { 
E [] newData = (E []) new new Object [newCatacity]; 
for (int I = 0; I <size; I ++) { 
newData [I] = Data [I]; 
} 
/ / reassigned to a new data member variable references (with a memory map described) 
data = newData; 
}
Copy the code

Draw a reference conversion expansion memory map

Test code

Copy the code
 public static void main(String[] args) {
        Array<Integer> array = new Array(5);
        array.addLast(1);
        array.addLast(2);
        array.addLast(3);
        array.addLast(4);
        array.addLast(5);
}
Copy the code

 

 

 

 


10.toString method
essence is: to create a StringBuilder object, and then append method, the contents of the array traversal, add StringBuilder object.

Copy the code
@Override
public String toString () {
StringBuilder stringBuilder = new StringBuilder();
//Format(String, Object, Object) 将指定的 String 中的格式项替换为两个指定的 Object 实例的值的文本等效项。
stringBuilder.append(String.format("size =%d ,capacity =%d\n ", size, data.length));
stringBuilder.append('[');
for (int i = 0; i < size; i++) {
stringBuilder.append(data[i]);
if (i != size -1) {
stringBuilder.append(',');
}
}
stringBuilder.append(']');

return stringBuilder.toString();
}
Copy the code

 

最后,

浮于表面看千遍,

不如自己思一遍,

希望这篇文章能够对你起到帮助。

 
分类:  数据结构
标签:  数据结构java动态数组

 

废话不多说,上代码

1.从类名开始(我真是太贴心了,给自己点个赞)

public class Array<E>

首先数组类需要带有泛型,这个不多说。需要注意的是在java中,数组只能存放同一个类型的。


2.成员变量

private int size; //数组中元素的个数
private E[] data; //数组声明


插个题外话:
关于size和索引,最开始学数组时让我很伤神,首先数组的索引是从0开始,而size是指数组中元素的
的个数,假设数组中有3个元素,那么size=3,而索引则为0,1,2。它们是差一位的,这个神奇的设计让我每次在写循环的界限条件时,
总要换算一下。
比如,遍历出数组的所有元素

for (int i = 0; i < size; i++) { }


我的心路历程是这样的:
  首先,第一步想,从0开始,到最后一位元素的索引位置结束,那么最后一位元素的索引是应该进来for循环的,那么i就应该
小于最后一位元素的索引的下一位,那么最后一位元素的索引的下一位是谁呢,对哦,size比索引大一位,那么应该是size,
所以应该i<size;
如果每次写for循环的界限时,都要这么想一下,白白消耗脑力阿。是不是只有我这么笨。
最后我的办法是转化成图来记在脑海里。每次用到的时候,直接脑海里浮现出这个图。

学习的本质就是将复杂的东西简单化。

 


3.构造方法
一种用户指定初始数组容量
一种用户不指定初始数组容量

Copy the code
public Array (int capacity) {
data = (E[])new Object[capacity];
size = 0;
}

public Array () {
this(10); //调用另一个构造方法,并默认初始容量为10
}
Copy the code


4.居家必备的基本方法

Copy the code
//获得数组元素个数
public int getSize () {
return size;
}
//获得数组长度
public int getCapacity () {
return data.length;
}
//获得数组是否为空
public boolean isEmpty () {
return size == 0;
}
Copy the code

 

5.添加方法

数组添加的本质就是:从后往前到指定索引位置,每个元素向后移一个格,给新来的腾出个地方。
重点:从后往前
Copy the code
//向数组指定位置添加元素,index为指定索引位置,e为添加的值
public void add (int index, E e) {
//索引位置不能让它瞎插,索引为负数,或者跳格子插,不可以。
if (index < 0 || index > size) {
throw new IllegalArgumentException("add is fail, require index < 0 || index > size");
}
//当数组容量满了的时候,调用扩容方法,此处给它扩当前数组长度的两倍。
if (data.length == size) {
this.resize(data.length * 2);
}for (int i = size - 1; i >= index; i--) {
data[i+1] = data[i];
}
//新来的进坑
data[index] = e;
//维护size
size ++;

}
Copy the code

 

Copy the code
//向数组第一位添加元素
public void addFirst (E e) {
//直接复用上一个add方法
this.add(0, e);
}
//向数组最后一位添加元素
public void addLast (E e) {
//同理
this.add(size, e);
}
Copy the code

 


6.删除方法(我个人分为两种,一种根据索引删除,一种根据值删除)

删除的本质:和添加相反,从要删除的索引位置的下一位开始,到最后一位元素索引位置结束,依次向前占一个坑。
重点:遍历的时候从前往后
Copy the code
//根据索引删除某个元素 返回删除的元素
public E remove (int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("remove is fail,require index < 0 || index >= size");
}
//先把要删除的元素存起来,不然等会就给覆盖了。
E value = data[index];
for (int i = index + 1; i < size; i++) {
data[i-1] = data[i];
}
//维护size
size --;
//此处为什么设置为null呢,因为泛型的原因,传进来的都是类对象,数组中存的是引用地址,引用不断开的话,垃圾回收器没办法回收。
data[size] = null;
//此处缩容,当数组元素个数等于数组长度四分之一时,进行缩容
if (size == data.length/4 && data.length / 2 != 0) { //缩容为数组长度的二分之一 this.resize(data.length /2); } return value; }
Copy the code

问题来了,为什么不在二分之一时就进行缩容呢?而是四分之一呢?
此处涉及到复杂度震荡问题,比较极端的一个情况是: 比如容量为10的一个数组, 此时该数组满了,此时要进来个元素,然后数组进行扩容,那么添加完元素此时数组的情况为容量为20, 内部有11个元素。 此时我再对数组进行删除一个元素,删除之后,数组元素个数变为10个,恰好为数组长度的二分之一, 那么自动进行缩容,以此类推,反复操作,每次扩容缩容的时间复杂度为O(n),所以此处应用了lazy的解决方案 就是等到数组元素个数为数组长度的四分之一时,再进行缩容,就可以避免这个问题。

 

Copy the code
//根据值删除某个元素
public void removeByValue (E e) {
//复用根据值查找元素的方法,返回索引(此方法在下面)
int index = this.getByElement(e);
if (index != -1) {
//复用根据索引删除的方法
this.remove(index);
}
}
//删除第一个元素
public E removeFirst () {
return this.remove(0);
}
//删除最后一个元素
public E removeLast () {
return this.remove(size - 1);
}
Copy the code

 


7.查找方法(同样分为两种,一种根据索引,一种根据值

Copy the code
//根据索引查找数组某个元素,返回值
public E getByIndex (int index) {

if (index < 0 || index >= size) {
throw new IllegalArgumentException("get is fail, require index < 0 || index >= size");
}

return data[index];
}
Copy the code

 

Copy the code
//根据值查找数组某个元素,返回索引
public int getByElement (E e) {
//本质:遍历数组进行比对
for (int i = 0; i < size; i++) {
if (data[i].equals(e) ) {
return i;
}
}
return -1;
}
Copy the code

 

Copy the code
//是否包含该元素
public boolean contains (E e) {
//本质:遍历数组进行比对
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) {
return true;
}
}
return false;
}
Copy the code

 


8.修改方法

Copy the code
//修改数组某个元素
public void set (int index, E e) {

if (index < 0 || index >= size) {
throw new IllegalArgumentException("set is fail, require index < 0 || index >= size");
}

data[index] = e;
}
Copy the code

 


9.扩容方法
扩容的本质:就是开辟个新数组,把旧数组的内容复制过去

Copy the code
private void resize (int newCatacity) {
E[] newData = (E[])new Object[newCatacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
//给成员变量data重新赋值新引用(后面有内存图介绍)
data = newData;
}
Copy the code

画个扩容引用转换的内存图

测试代码

Copy the code
 public static void main(String[] args) {
        Array<Integer> array = new Array(5);
        array.addLast(1);
        array.addLast(2);
        array.addLast(3);
        array.addLast(4);
        array.addLast(5);
}
Copy the code

 

 

 

 


10.toString方法
本质就是:创建一个StringBuilder对象,然后通过append方法,将数组的内容遍历,添加进StringBuilder对象。

Copy the code
@Override 
public String toString () { 
the StringBuilder StringBuilder the StringBuilder new new = (); 
// the Format (String, Object, Object) Replaces the format specified in the text String equivalent values of the two specified Object instance. 
StringBuilder.Append (String.format ( "size =% D, D Capacity =% \ n-", size, data.length)); 
StringBuilder.Append ( '['); 
for (int I = 0; I <size; ++ I) { 
StringBuilder.Append (Data [I]); 
IF (I size = -1) {! 
StringBuilder.Append ( ','); 
} 
} 
StringBuilder.Append ( ']'); 

return StringBuilder.ToString (); 
}
Copy the code

 

At last,

Floating on the surface look a thousand times,

As their own thinking again,

I hope this article will be of assistance to you.

Guess you like

Origin www.cnblogs.com/xichji/p/11717638.html
Recommended