数据结构与算法-数组

 思考这样一道题目:

给你一个文件(近6G的文件)里面包含了全国人民(大约14亿)的年龄数据(大约是0~180左右),现在需要统计每个年龄段有多少人?

单机+2cpu+2G内存 以上情况你如何以最高效的的方法来解决这个问题?

用数组来解决: int[0] 这个下标0表示年龄 int[0] 的值是表示0岁的有多少人

  String str = null;
       String fileName = "D:\\age.txt";   //这个就是全部年龄数据文件
       InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName),"UTF-8");

       long start = System.currentTimeMillis();
       BufferedReader br = new BufferedReader(isr);
       int tot = 0 ;
       int data [] = new int[200];
       while((str = br.readLine()) != null){ //一行一行的读 O(n)
           int age = Integer.valueOf(str);
           data[age] ++ ;
           tot ++ ;
      }
       System.out.println("总共的数据大小: " + tot);   //总共的数据大小: 1400000000

       for(int i = 0 ; i < 200 ; i ++){//下标从0开始的
           System.out.println(i + ":" + data[i]);
      }
       System.out.println("计算花费的时间为:" + (System.currentTimeMillis() - start) + "ms"); //计算花费的时间为:89170ms

 

1、数组的定义

  数组是指有序的元素序列。如果将有限个类型相同的变量的集合命名,那么这个名称就是数组名,而组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组各个元素的数字编号称为下标。数组在程序设计中,为了处理方便,把具有相同类型的的若干元素组织起来的一种形式,这些无序排列的同类数据元素的集合称为数组。

2、数组的特点

  1、数组是相同数据类型的元素集合。

  2、数组当中的各个元素存储是有先后顺序的,他们在内存中按照这个先后顺序连续的存放在一起。

  3、数组元素用整个数组的名字和它自己在数组中的顺序位置来表示。例如,a[0]表示名字为a的数组中的第一个元素,a[1]代表数组a的第二个元素,以此类推。

3、表现形式

  1、一维数组

    int a[], String a[]

  2、多维数组

    Int a,int a[]

4、随机访问

  数组是连续的内存空间和相同类型的数据。正是因为这两个限制,它才有了一个非常重要的特性:随机访问,也就是查询是非常快速的且高效的,但有利就有弊,这两个限制也让数组的很多操作变得非常低效,比如要想在数组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。

 

这是简单的数组增删元素的内存示意图

数据结构与算法-数组

 

 

 

这个是数组操作的简单代码实现 其实也是我们常用的ArrayList代码的简单实现,当然JDK封装的ArrayList的实现更复杂,涉及到扩容什么的。

public class ArrayTest {

   private int arraySize;  //数组长度
   private int data[];
   private int index;      //当前已经存的数大小

   /**
    * 构造函数初始化
    * @param arraySize
    */
   public ArrayTest(int arraySize){
       this.arraySize = arraySize;
       data = new int[arraySize];
       this.index = 0;
  }

   /**
    * 简单打印
    */
   public void print(){
       System.out.println("index:"+index);
       for (int i = 0; i <index ; i++) {
           System.out.println(data[i]+" ");
      }
       System.out.println();
  }

   /**
    * 数组添加元素
    * @param loc
    * @param n
    */
   public void add(int loc,int n){     //时间复杂度   分析极端情况 从第一个元素插入 时间复杂度就是O(n) 最后一个元素插入时间复杂度就是O(1)
       if(index++ < arraySize){
           for (int i = arraySize-1; i > loc ; i--) {
               data[i] = data[i-1];
          }
           data[loc] = n;
      }
  }

   /**
    * 数组删除元素
    * @param loc
    */
   public void delete(int loc){ //时间复杂度   分析极端情况 从第一个元素删除 时间复杂度就是O(n) 最后一个元素删除时间复杂度就是O(1)
       for (int i = loc; i < arraySize ; i++) {
           if(i!= arraySize-1){   //
               data[i] = data[i+1];
          }else{
               data[i] = 0;
          }
      }
       index--;
  }

   /**
    * 数组更新元素
    * @param loc
    * @param n
    */
   public void update(int loc,int n){ //时间复杂度 O(1)
       data[loc] = n;
  }

   /**
    * 数组的查询
    * @param loc
    * @return
    */
   public int get(int loc){ //时间复杂度 O(1)
       return data[loc];
  }

}

ArrayList和数组:

  其实他们本质是一样的,都是数组。

  ArrayList是JDK封装的 提供了操作数组的api,包括扩容操作也实现了。

  数组操作的话需要自己全部实现。

ArrayList和数组选择:

  不知道数组大小的情况下选择ArrayList

  如果知道大小且对性能要求很高的话,选择数组。

 

数组最需要注意的就是数组越界 ArrayIndexOutOfBoundsException

 

 

为什么很多计算机编程语言中的数组下标是从0开始的?

  当我们定义数组的时候,根据数组的特点(连续的)在内存分配空间的时候,分配是一段连续的内存空间

  如 int a = new int[3]

  假如申请的内控地址是 10001 10002 10003

  int[0] ==> 10001 ==> 10001+0*typesize

  int[1] ==> 10002 ==> 10001+1*typesize

  int[2] ==> 10003 ==> 10001+2*typesize

  后面的 0 1 2就是对应前面数组的下标

 

  假如我们不是从0开始 而是1开始

  int[1] ==> 10001 ==> 10001+(1-1)*typesize

  int[2] ==> 10002 ==> 10001+(2-1)*typesize

  int[3] ==> 10003 ==> 10001+(3-1)*typesize

  这样就多了一步的底层运算 而且了解计算机底层计算的话,减法运算其实就是加一个负数 ,其中会涉及到反码补码等操作。

 

 

 

 

 

上一篇:Python数据结构大结局:DataFrame


下一篇:如何使用腾讯位置服务地图选点组件?