java 队列与泛型——动态数组的实现原理

java 队列与泛型——动态数组的实现原理

学习本文需要用到的知识:java数组

1、思路推理

众所周知,在很多编程语言中,数组的大小一旦确定,在定义后是不可以改变的。如果数组储存满了之后还想往数组里面储存元素,肯定不能接着用同一个数组。所以需要重新定义一个比原数组要大的数组,把原数组里的数据重新储存到新数组,再把新数据储存进去。代码如下:

public class MyArray {
       //声明初始数组
       private  Object[] array;
       //用于储存数组的大小
       private  int size;
       //在对象被创建时创建数组,初始大小为0
       public MyArray() {
              array = new Object[0];
       }
       public boolean add(Object newPart) {
              // 创建一个新数组
              Object[] newArray = new Object[size + 1];
              // 将原有的数组的内容赋给新数组
                  for (int i = 0; i < array.length; i++) {
                     newArray[i] = array[i]; 
              }
              //添加的数据写入新数组
              newArray[size++]  = newPart;
             //将数组array指向newArray
              array = newArray;
              return true;
       }

}

上述代码实现的MyArray对象可以实现储存任意个元素,但有两个明显的缺陷:

缺陷一:**可以在同一个MyArray对象里面储存任意的对象。**这貌似很不错,但在实际使用中,很多地方都只需要储存同一类的对象,用以上的方法无法判断所储存的元素是否是同一个类的对象。这就需要用到泛型。

泛型允许我们使用E、K、V等字母()来代替不确定的数据类型(注意:E、K、V等字母不属于数据类型,只是一个符号,不能用在数据类型需要确定的地方这里的数据类型不包括基本数据类型,如果需要用到基本数据类型,则用基本数据类型对应的类来替代)。具体方法如下:

首先在类名后加“<>”,尖括号里用E代替用户需要使用的数据类型:

public class MyArray<E> {……………}

然后将类的成员里面,不确定的数据类型都用E替代,替代后完整代码如下:

public class MyArray<E> {
   //声明初始数组
   private Object[] array;
   //用于储存数组的大小
   private int size;
   //在对象被创建时创建数组,初始大小为0
   public MyArray() {
          array= new Object[0];
   }
   public boolean add(E newPart) {        
          //创建一个新数组
          Object[] newArray = new Object[size + 1];
          //将原有的数组的内容赋给新数组
          for(int i = 0; i < array.length; i++) {
                 newArray[i]= array[i];
          }
          //添加的数据写入新数组
          newArray[size++]= newPart;
          //将数组array指向newArray
          array= newArray;
          return true;
   }
}

缺陷二:每储存一个数据就需要新定义一个数组,效率低下。我们可以给MyArray添加一个储存比例,让其初始化的时候有一定的大小(增长比例),等数据储存过量时再创建新数组,而且这个数组的大小要比原数组增加一定的大小(增长比例),而不是只增加一。另外,在存入数据时,需要先判断原数组里面是否有空值,有的话就将数据直接存入,没有再创建新数组。完整代码如下:

public class MyArray<E> {
       private Object[] array;
       private int size;
       private int addScale = 5; // 设置增长比例,这里暂时设置为5
       public  MyArray() {
        //初始大小由增长比例来确定
              array = new Object[addScale];
       }
       public boolean add(E newPart) {
             //检查之前数组是否有空的元素,如果有,则将添加内容补充到空元素
              for (int i = 0; i < size; i++) {
                     if  (array[i] == null) {
                            array[i]  = newPart;
                            return true;
                     }
              }
              //创建一个新数组
             // 按增长比例定义新数组,以提高效率
              Object[] newArray = new Object[size + addScale];
              //将原有的数组的内容赋给新数组
              for (int i = 0; i < array.length; i++) {
                     newArray[i]  = array[i];
              }
              //添加的数据写入新数组
              newArray[size]= newPart;
              size = size + addScale;
              array= newArray;
              return true;
       }

2、其它方法的实现

(1)、在指定的位置添加新元素:

        // 在索引为index的地方插入newPart
               public boolean add(int index, E newPart) {
                  if(index < 0 || index > size)
                         return false;
                  if(index == size) {
                         add(newPart);
                         return true;
                  }
                  add((E) null);
                  for (int i = size - 1; i > index; i--) {
                         array[i]= array[i - 1];
                  }
                  array[index] = newPart;
                  return true;
           }

(2)、往数组里添加数组:

    // 往数组里添加数组
 public void add(MyArray<E> e) {
              for(int i = 0; i < e.size(); i++) {
                   if(e.get(i) != null) {
                             //利用已经定义的add函数
                            add((E)e.get(i));
                     }
              }
       }

(3)、在指定位置插入某个元素

// 在索引为index的地方插入newPart
       public boolean add(int index, E newPart) {
              if(index < 0 || index > size)
                     return false;
              if(index == size) {
                     add(newPart);
                     return true;
              }
              add((E)null);
              for (int i = size - 1; i > index; i--) {
                     array[i]= array[i - 1];
              }
              array[index] = newPart;
              return true;
       }

(4)、在指定位置插入数组:

// 将数组插入索引为index的元素前

   public int add(int index, MyArray<E> e) {
          int count = 0;
          if(index < 0 || index > size)
                 return count;
          for(int i = 0; i < e.size(); i++) {
         //利用(3)里的函数来实现插入单个元素
                 add(index+i,(E)e.get(i));
                 count++;
          }
          return count;
   }

(5)、将指定位置的元素替换成新元素:

// 将索引为index的数据替换为newPart

   public boolean update(int index, E newPart) {

          if(index < 0 || index >= size)
                 return false;
          else{
                 array[index]= newPart;
                 return true;
          }
   }

(6)、将指定的第一个元素替换成新元素:

// 将第一个内容为e的元素替换为newPart

       public boolean update(E e, E newPart) {

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

                     if(array[i] == e) {
                            array[i]    = newPart;
                            return true;
                     }
              }
              return false;
       }

(7)、将指定的所有元素替换成新元素:

  // 将所有内容为e的元素替换为newPart,返回值为替换的元素个数

   public int updateAll(E e, E newPart) {
          int count = 0;
          for(int i = 0; i < size; i++) {
                 if(array[i] == e) {
                        array[i] = newPart;
                        count++;
                 }
          }
          return count;
   }

(8)、移除第一个指定的元素:

 // 如果元素deletePart存在,则删除第一个deletePart元素
   public boolean remove(E deletePart) {
          for(int i = 0; i < size; i++) {
                 if(get(i) == deletePart) {
                        array[i] = null;
                        complement(i);
                        return true;
                 }
          }
          return false;
   }

 // 将所有靠后的数据向前面为空的索引替换补全
   public void complement(int index) {
          for(int j = index; j < size - 1; j++) {
                 array[j] = array[j + 1];
          }
          size--;
   }

(9)、执行指定索引的元素:

// 删除索引为index的元素,返回值为删除的元素
   public E remove(int index) {
          if(index < 0 || index > size) {
                 return null;
          }
          E removePart = (E) array[index];
          array[index] = null;
          complement(index);
          return removePart;
   }

// 将所有靠后的数据向前面为空的索引替换补全
   public void complement(int index) {
          for(int j = index; j < size - 1; j++) {
                 array[j] = array[j + 1];
          }
          size--;
   }

(10)、移除所有指定的元素:

    // 删除所有元素和deletePart相同的内容,返回值为更改的元素数量
   public int removaAll(E deletePart) {
          int count = 0;
          for(int i = 0; i < size; i++) {
                 if(array[i] == deletePart) {
                        array[i] = null;
                        complement(i);
                        i--;
                        count++;
                 }
          }
          return count;
   }



// 将所有靠后的数据向前面为空的索引替换补全
   public void complement(int index) {
          for(int j = index; j < size - 1; j++) {
                 array[j] = array[j + 1];
          }
          size--;
   }

(11)、获取指定索引的元素:

// 获取索引为index的元素

   public Object get(int index) {

          return array[index];
   }

(12)、获取数组的大小

  // 获取数组的大小

   public int size() {
          return size;
   }

猜你喜欢

转载自blog.csdn.net/weixin_41475710/article/details/82876573