zoukankan      html  css  js  c++  java
  • 第二十二篇 玩转数据结构——构建动态数组

     
     
     
    1.. 数组基础
    • 数组就是把数据码成一排进行存放。
    • Java中,数组的每个元素类型必须相同,可以都为int类型,string类型,甚至是自定义类型。
    • 数组的命名要语义化,例如,如果数组用来存放学生的成绩,那么命名为scores就比较合适。
    • 索引(index)是数组中的一个重要概念,它是我们给数组中的每个元素分配的编号,从0开始,依次递增。如果数组中存放了n个元素,第一个元素的索引是0,最后一个元素的索引是n-1。
    • 通过索引,我们可以对数组中的元素进行快速访问,例如,我们访问索引为2的元素也就是数组中的第3个元素,就可以通过scores[2]这种形式。
    • 在Java中声明一个简单的数组
    • public class Main {
      
          public static void main(String[] args) {
              int[] arr = new int[10];
              for (int i = 0; i < arr.length; i++)
                  arr[i] = i;
          }
      }
    • 声明一个有初始值的数组
    • public class Main {
      
          public static void main(String[] args) {
              int[] scores = new int[]{100, 99, 86};
              for (int i = 0; i < scores.length; i++)
                  System.out.println(scores[i]);
          }
      }
    • for循环的另一种使用形式
    • public class Main {
      
          public static void main(String[] args) {
              int[] scores = new int[]{100, 99, 86};
              for (int score : scores)
                  System.out.println(score);
          }
      }
    • 修改数组中的元素
    • socres[1] = 98;
    • 数组的索引可以是语义化的,也可以是非语义化的。
    • 数组的最大优点,就是可以通过索引对数据进行快速查询,因此,我们倾向于使用语义化的索引,这样我们就很清楚自己在查什么。
    • 如果我们的应用场景中,索引没有语义,那么使用其它数据结构可能是更好的选择。
    • 对于一些特殊应用场景,虽然使用了语义化索引,但依然不适合使用数组,例如,身份证号,我们不能使用身份证号来作为数组的索引,因为这个数字太大了,会导致巨大的空间浪费。
    • 如果数组的索引是非语义化的,我们就需要考虑很多问题,例如,当数组的空间未被填满时,如何表示空位处的元素?如何向数组中添加新的元素?如何删除掉数组中原有的元素?等等。Java所提供的原生数组是无法解决这些问题的,我们需要定制属于自己的数组类Array,即,基于Java的原生数组,二次封装属于我们自己的数组类。

    2.. 实现自定义数组类Array所包含的基本方法:

    • public class Array {
      
          private int[] data;  //设置为private,不希望用户从外部直接获取这些信息,防止用户篡改数据
          private int size;
      
          //构造函数,传入数组的容量capacity构造Array
          public Array(int capacity) {
              data = new int[capacity];
              size = 0;
          }
      
          //无参数构造函数,默认数组容量capacity=10
          public Array() {
              this(10);    //这里的capacity是IDE自动添加的提示信息,实际不存在
          }
      
          //获取数组中的元素个数
          public int getSize() {
              return size;
          }
      
          //获取数组的容量
          public int getCapacity() {
              return data.length;
          }
      
          //判断数组是否为空
          public boolean isEmpty() {
              return size == 0;
          }
      }

    3.. 实现向自定义数组中添加元素的方法

    • 向数组中添加元素的最简单的方法就是向数组的末尾添加元素
    • //向数组末尾添加一个新元素
      public void addLast(int e) {
      
          if (size == data.length) {
              throw new IllegalArgumentException("AddLast failed. Array is full.");
          }
      
          data[size] = e;
          size++;
      }
    • 向数组中指定索引位置插入一个元素
    • //在index位置插入一个新元素e
      public void add(int index, int e) {
      
          if (size == data.length) {
              throw new IllegalArgumentException("Add failed. Array is full.");
          }
      
          if (index < 0 || index > size) {
              throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
          }
      
      
          for (int i = size - 1; i >= index; i--) {
              data[i + 1] = data[i];
          }
      
          data[index] = e;
          size++;
      }
    • 定义完向数组中指定索引位置插入一个元素的方法add之后,我们之前定义的向数组末尾插入元素的方法addLast其实可以调用add方法来实现,我们调整addLast方法如下:
    • //向数组末尾添加一个新元素
      public void addLast(int e) {
          add(size, e);
      }
    • 我们还可以调用add方法实现一个向数组开头添加一个新元素的方法
    • //向数组开头添加一个新元素
      public void addFirst(int e) {
          add(0, e);
      }

    4.. 实现在数组中查询元素和修改元素的方法

    • 实现自定义打印数组格式
    • @Override
      public String toString() {    //覆盖父类的toString方法
      
          StringBuilder res = new StringBuilder();
      
          res.append(String.format("Array: size=%d, capacity=%d
      ", size, data.length));
          res.append('[');
          for (int i = 0; i < size; i++) {
              res.append(data[i]);
              if (i != size - 1) {
                  res.append(", ");
              }
          }
          res.append(']');
      
          return res.toString();
      }
    • 在main函数中进行测试:
    • public class Main {
      
          public static void main(String[] args) {
      
              Array arr = new Array(20);
              for (int i = 0; i < 10; i++) {
                  arr.addLast(i);    //测试addLast方法
              }
              System.out.println(arr);
      
              arr.add(1, 100);     //测试add方法
              System.out.println(arr);
      
              arr.addFirst(-1);    //测试addFirst方法
              System.out.println(arr);
          }
      
      }
    • 打印效果如下:
    • Array: size=10, capacity=20
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=12, capacity=20
      [-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    • 实现获取指定索引元素的方法
    • //获取index位置的元素
      public int get(int index) {
          if (index < 0 || index >= size) {
              throw new IllegalArgumentException("Get failed. Index is illegal.");
          }
          return data[index];
      }
    • 实现修改指定索引元素的方法
    • //修改index位置的元素为e
      public void set(int index, int e) {
          if (index < 0 || index >= size) {
              throw new IllegalArgumentException("Set failed. Index is illegal.");
          }
          data[index] = e;
      }
    • 实现查看数组中是否包含元素e的方法
    • //查找数组中是否存在元素e
      public boolean contains(int e) {
          for (int i = 0; i < size; i++) {
              if (data[i] == e) {
                  return true;
              }
          }
          return false;
      }
    • 实现查看数组中指定元素的索引的方法,若找不到,返回-1
    • //查看数组中元素e的索引,若找不到元素e,返回-1
      public int find(int e){
          for(int i=0;i<size;i++){
              if(data[i] == e){
                  return i;
              }
          }
          return -1;
      }
    • 实现删除数组中指定索引的元素的方法
    • //删除掉index位置的元素,并且返回所删除的元素
      public int remove(int index) {
      
          if (index < 0 || index >= size) {
              throw new IllegalArgumentException("Add failed. Require index >= 0 and index < size");
          }
      
          int ret = data[index];
      
          for (int i = index + 1; i < size; i++) {
              data[i - 1] = data[i];
          }
          size--;
          return ret;
      }
      
      //删除掉数组开头的元素,并返回所删除的元素
      public int removeFirst() {
          return remove(0);
      }
      
      //删除掉数组末尾的元素,并返回所删除的元素
      public int removeLast() {
          return remove(size - 1);
      }
      
      //如果数组中有元素e,那么将其删除,否则什么也不做
      public void removeElement(int e) {
          int index = find(e);
          if (index != -1) {
              remove(index);
          }
      }

    5.. 整理我们目前实现的业务逻辑:

    • public class Array {
      
          private int[] data;  //设置为private,不希望用户从外部直接获取这些信息,防止用户篡改数据
          private int size;
      
          //构造函数,传入数组的容量capacity构造Array
          public Array(int capacity) {
              data = new int[capacity];
              size = 0;
          }
      
          //无参数构造函数,默认数组容量capacity=10
          public Array() {
              this(10);    //这里的capacity是IDE自动添加的提示信息,实际不存在
          }
      
          //获取数组中的元素个数
          public int getSize() {
              return size;
          }
      
          //获取数组的容量
          public int getCapacity() {
              return data.length;
          }
      
          //判断数组是否为空
          public boolean isEmpty() {
              return size == 0;
          }
      
          //向数组末尾添加一个新元素e
          public void addLast(int e) {
              add(size, e);
          }
      
          //向数组开头添加一个新元素e
          public void addFirst(int e) {
              add(0, e);
          }
      
          //在index位置插入一个新元素e
          public void add(int index, int e) {
      
              if (size == data.length) {
                  throw new IllegalArgumentException("Add failed. Array is full.");
              }
      
              if (index < 0 || index > size) {
                  throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
              }
      
      
              for (int i = size - 1; i >= index; i--) {
                  data[i + 1] = data[i];
              }
              data[index] = e;
              size++;
          }
      
          //获取index位置的元素
          public int get(int index) {
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Get failed. Index is illegal.");
              }
              return data[index];
          }
      
          //修改index位置的元素为e
          public void set(int index, int e) {
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Set failed. Index is illegal.");
              }
              data[index] = e;
          }
      
          //查找数组中是否存在元素e
          public boolean contains(int e) {
              for (int i = 0; i < size; i++) {
                  if (data[i] == e) {
                      return true;
                  }
              }
              return false;
          }
      
          //查看数组中元素e的索引,若找不到元素e,返回-1
          public int find(int e) {
              for (int i = 0; i < size; i++) {
                  if (data[i] == e) {
                      return i;
                  }
              }
              return -1;
          }
      
          //删除掉index位置的元素,并且返回删除的元素
          public int remove(int index) {
      
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Remove failed. Index is illegal.");
              }
      
              int ret = data[index];
      
              for (int i = index + 1; i < size; i++) {
                  data[i - 1] = data[i];
              }
              size--;
              return ret;
          }
      
          //删除掉数组开头的元素,并返回删除的元素
          public int removeFirst() {
              return remove(0);
          }
      
          //删除掉数组末尾的元素,并返回删除的元素
          public int removeLast() {
              return remove(size - 1);
          }
      
          //如果数组中有元素e,那么将其删除,否则什么也不做
          public void removeElement(int e) {
              int index = find(e);
              if (index != -1) {
                  remove(index);
              }
          }
      
      
          @Override
          public String toString() {    //覆盖父类的toString方法
      
              StringBuilder res = new StringBuilder();
              res.append(String.format("Array: size=%d, capacity=%d
      ", size, data.length));
              res.append('[');
              for (int i = 0; i < size; i++) {
                  res.append(data[i]);
                  if (i != size - 1) {
                      res.append(", ");
                  }
              }
              res.append(']');
              return res.toString();
          }
      }

    6.. 现在我们的自定义数组的元素只允许为int类型,我们需要进行优化,让数组可以放置"任意"类型的元素,解决这个问题的技术称之为"泛型"。这里的"任意"加了引号,这是因为在Java中一个泛型类并不能放置任意数据类型的元素,泛型不能放置基本数据类型,只能放置类对象。在Java中,共有8中基本数据类型:int、short、long、boolean、byte、char、float、double。如果将数组设置成泛型数组,那么就无法放置这些基本数据类型了。为了解决这个问题,Java语言为每个基本数据类型都设计了一个包装类,把本来不是类对象的数据包装成了类对象。这8中基本数据类型所对应的包装类分别为:Int、Short、Long、Boolean、Byte、Char、Float、Double,在需要的情况下,包装类与其对应的基本数据类型可以自动进行转换。

     
    7.. 优化后,Array类的业务逻辑如下:
    • public class Array<E> {
      
          private E[] data;  //设置为private,不希望用户从外部直接获取这些信息,防止用户篡改数据
          private int size;
      
          //构造函数,传入数组的容量capacity构造Array
          public Array(int capacity) {
              data = (E[]) new Object[capacity];
              size = 0;
          }
      
          //无参数构造函数,默认数组容量capacity=10
          public Array() {
              this(10);    //这里的capacity是IDE自动添加的提示信息,实际不存在
          }
      
          //获取数组中的元素个数
          public int getSize() {
              return size;
          }
      
          //获取数组的容量
          public int getCapacity() {
              return data.length;
          }
      
          //判断数组是否为空
          public boolean isEmpty() {
              return size == 0;
          }
      
          //向数组末尾添加一个新元素e
          public void addLast(E e) {
              add(size, e);
          }
      
          //向数组开头添加一个新元素e
          public void addFirst(E e) {
              add(0, e);
          }
      
          //在index位置插入一个新元素e
          public void add(int index, E e) {
      
              if (size == data.length) {
                  throw new IllegalArgumentException("Add failed. Array is full.");
              }
      
              if (index < 0 || index > size) {
                  throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
              }
      
      
              for (int i = size - 1; i >= index; i--) {
                  data[i + 1] = data[i];
              }
              data[index] = e;
              size++;
          }
      
          //获取index位置的元素
          public E get(int index) {
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Get failed. Index is illegal.");
              }
              return data[index];
          }
      
          //修改index位置的元素为e
          public void set(int index, E e) {
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Set failed. Index is illegal.");
              }
              data[index] = e;
          }
      
          //查找数组中是否存在元素e
          public boolean contains(E e) {
              for (int i = 0; i < size; i++) {
                  if (data[i].equals(e)) {
                      return true;
                  }
              }
              return false;
          }
      
          //查看数组中元素e的索引,若找不到元素e,返回-1
          public int find(E e) {
              for (int i = 0; i < size; i++) {
                  if (data[i].equals(e)) {
                      return i;
                  }
              }
              return -1;
          }
      
          //删除掉index位置的元素,并且返回删除的元素
          public E remove(int index) {
      
              if (index < 0 || index >= size) {
                  throw new IllegalArgumentException("Remove failed. Index is illegal.");
              }
      
              E ret = data[index];
      
              for (int i = index + 1; i < size; i++) {
                  data[i - 1] = data[i];
              }
              size--;   //data[size]会指向一个类对象,这部分空间不会被释放loitering objects
              data[size] = null;
              return ret;
          }
      
          //删除掉数组开头的元素,并返回删除的元素
          public E removeFirst() {
              return remove(0);
          }
      
          //删除掉数组末尾的元素,并返回删除的元素
          public E removeLast() {
              return remove(size - 1);
          }
      
          //如果数组中有元素e,那么将其删除,否则什么也不做
          public void removeElement(E e) {
              int index = find(e);
              if (index != -1) {
                  remove(index);
              }
          }
      
      
          @Override
          public String toString() {    //覆盖父类的toString方法
      
              StringBuilder res = new StringBuilder();
              res.append(String.format("Array: size=%d, capacity=%d
      ", size, data.length));
              res.append('[');
              for (int i = 0; i < size; i++) {
                  res.append(data[i]);
                  if (i != size - 1) {
                      res.append(", ");
                  }
              }
              res.append(']');
              return res.toString();
          }
      }

    8.. 再次在main方法中实例化我们的自定义数组,进行测试:

    • public class Main {
      
          public static void main(String[] args) {
      
              Array<Integer> arr = new Array<>(20);
              for (int i = 0; i < 10; i++) {
                  arr.addLast(i);
              }
              System.out.println(arr);
      
              arr.add(1, 100);
              System.out.println(arr);
      
              arr.addFirst(-1);
              System.out.println(arr);
      
              arr.remove(2);
              System.out.println(arr);
      
              arr.removeElement(4);
              System.out.println(arr);
      
              arr.removeFirst();
              System.out.println(arr);
      
              arr.removeLast();
              System.out.println(arr);
          }
      }
    • 输出结果如下:
    • Array: size=10, capacity=20
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=12, capacity=20
      [-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=10, capacity=20
      [-1, 0, 1, 2, 3, 5, 6, 7, 8, 9]
      Array: size=9, capacity=20
      [0, 1, 2, 3, 5, 6, 7, 8, 9]
      Array: size=8, capacity=20
      [0, 1, 2, 3, 5, 6, 7, 8]

    9.. 测试让自定义数组去承载对象

    • public class Student {
      
          private String name;
          private int score;
      
          public Student(String studetName, int studentScore) {
              name = studetName;
              score = studentScore;
          }
      
          @Override
          public String toString() {
              return String.format("Student(name: %s, score: %d)", name, score);
          }
      
          public static void main(String[] args) {
      
              Array<Student> arr = new Array<>();
      
              arr.addLast(new Student("XueZou", 98));
              arr.addLast(new Student("Guiche", 100));
              arr.addLast(new Student("QUiShui", 99));
      
              System.out.println(arr);
          }
      }
    • 输出结果如下:
    • Array: size=3, capacity=10
      [Student(name: XueZou, score: 98), Student(name: Guiche, score: 100), Student(name: QUiShui, score: 99)]
     
    10.. 动态数组,即数组的容量可伸缩
    • 修改add方法的业务逻辑,使自定义数组支持扩容
    • //在index位置插入一个新元素e
      public void add(int index, E e) {
      
          if (index < 0 || index > size) {
              throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size");
          }
      
          if (size == data.length) {
              resize(2 * size); //扩大为原容量的2倍
          }
      
      
          for (int i = size - 1; i >= index; i--) {
              data[i + 1] = data[i];
          }
          data[index] = e;
          size++;
      }
    • 我们需要实现resize方法,业务逻辑如下:
    • private void resize(int newCapacity) {
          E[] newData = (E[]) new Object[newCapacity];
          for (int i = 0; i < size; i++) {
              newData[i] = data[i];
          }
          data = newData;
      }
    • 实现扩容后,进行测试:
    • public static void main(String[] args) {
      
          Array<Integer> arr = new Array<>();
          for (int i = 0; i < 10; i++) {
              arr.addLast(i);
          }
          System.out.println(arr);
      
          arr.add(1, 100);
          System.out.println(arr);
      
          arr.addFirst(-1);
          System.out.println(arr);
      }
    • 输出效果如下:
    • Array: size=10, capacity=10
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=12, capacity=20
      [-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    • 修改remove方法,使数组中的元素减少到一定程度时,自动缩小数组容量
    • //删除掉index位置的元素,并且返回删除的元素
      public E remove(int index) {
      
          if (index < 0 || index >= size) {
              throw new IllegalArgumentException("Remove failed. Index is illegal.");
          }
      
          E ret = data[index];
      
          for (int i = index + 1; i < size; i++) {
              data[i - 1] = data[i];
          }
          size--;   //data[size]会指向一个类对象,这部分空间不会被释放loitering objects
          data[size] = null;
      
          if (size == data.length / 2) {
              resize(data.length / 2);  //被利用的空间等于总空间的一半时,将数组容量减少一半
          }
          return ret;
      }
    • 实现自动降低容量后,进行测试:
    • public static void main(String[] args) {
      
          Array<Integer> arr = new Array<>();
          for (int i = 0; i < 10; i++) {
              arr.addLast(i);
          }
          System.out.println(arr);
      
          arr.add(1, 100);
          System.out.println(arr);
      
          arr.addFirst(-1);
          System.out.println(arr);
      
          arr.remove(2);
          System.out.println(arr);
      
          arr.removeElement(4);
          System.out.println(arr);
      
          arr.removeFirst();
          System.out.println(arr);
      }
    • 输出效果如下:
    • Array: size=10, capacity=10
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=12, capacity=20
      [-1, 0, 100, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=11, capacity=20
      [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      Array: size=10, capacity=10
      [-1, 0, 1, 2, 3, 5, 6, 7, 8, 9]
      Array: size=9, capacity=10
      [0, 1, 2, 3, 5, 6, 7, 8, 9]
    11.. 简单的时间复杂度分析
    • O(1), O(n), O(lgn), O(nlgn), O(n^2)
    • 大O描述的是算法的运行时间和输入数据之间的关系
    • 通常我们会说下面的这段代码的算法是O(n)的,n在这里简单理解为nums中的元素个数,O(n)是说下面这段代码的运行效率,与nums中的元素个数n是呈线性关系的,线性关系体现在n是一次方。
    • public static int sum(int[] nums) {
        int sum = 0;
          for (int num: nums) {
              sum += num;
          return sum;
          }
    • 按照这个思路我们对上面所实现的方法,挨个分析一下它们的算法的时间复杂度:添加操作中addLast(e)方法的时间复杂度是O(1),这表示我们的算法所消耗的时间与我们数据的规模没有关系,这里所指的数据规模是我们数组中的元素个数;addFirst(e)方法的时间复杂度是O(n),因为每个元素都需要向后移动一位;add(index, e)方法的时间复杂度与index的具体取值相关,它的时间复杂度也是O(n);综合来看,添加操作是一个O(n)级别的算法。
    • 删除操作中,removeLast(e)方法的时间复杂度是O(1);removeFirst(e)的时间复杂度是O(n);remove(index, e)的时间复杂度也是O(n);综合来看,删除操作的时间复杂度也是O(n)。
    • 修改操作set(index, e)的时间复杂度是O(1),这是数组的最大优势,专业术语称为"支持随机访问"。
    • 查询操作中,get(index)方法的时间复杂度是O(1);find(e)方法和contains(e)方法的时间复杂度都是O(n)。
    12.. 总的来看,对于动态数组来说,增删改查四种操作:
    • 增:时间复杂度O(n);
    • 删:时间复杂度O(n);
    • 改:已知索引O(1),未知索引O(n);
    • 查:已知索引O(1),未知索引O(n);
    • 因此,索引具有语义时,选择数组是非常好的,我们可以通过索引轻松检索数据中的内容。
     
    13.. resize的时间复杂度分析
    • 对于添加操作,如果我们只使用addLast方法,那么它的时间复杂度本来应该是O(1),但是,由于存在resize方法,而resize方法的时间复杂度是O(n),所以addLast方法的时间复杂度就不是O(1)了,但是它的均摊复杂度是O(1);
    • 类似的对于删除操作,如果只使用removeLast方法,那么它的均摊复杂度也是O(1);
    14.. 复杂度震荡
    • 复杂度震荡,是指我们在数组容量的临界位置交替进行添加和删除操作,这会导致数组不断执行扩容和缩容操作,而扩容和缩容的时间复杂度都是O(n),出现这种问题的原因在于,我们执行removeLast方法后,resize得有点着急(Eager),解决方案是使用更加懒惰的策略(Lazy),简单理解就是,当数组占用量刚好减到1/2时,不着急缩容,等减到1/4时,再触发缩容,只缩1/2。
    • 我们需要稍微改动一下remove方法,如下所示:
    • public E remove(int index) {
      
          if (index < 0 || index >= size) {
              throw new IllegalArgumentException("Remove failed. Index is illegal.");
          }
      
          E ret = data[index];
      
          for (int i = index + 1; i < size; i++) {
              data[i - 1] = data[i];
          }
          size--;   //data[size]会指向一个类对象,这部分空间不会被释放loitering objects
          data[size] = null;
      
          if (size == data.length / 4 && data.length / 2 != 0) {       //改动在这里
              resize(data.length / 2);  //被利用的空间等于总空间的一半时,将数组容量减少一半
          }
          return ret;
      }
  • 相关阅读:
    hive与hbase整合
    待重写
    hive DML
    【知识强化】第六章 总线 6.1 总线概述
    【知识强化】第五章 中央处理器 5.1 CPU的功能和基本结构
    【知识强化】第四章 指令系统 4.3 CISC和RISC的基本概念
    【知识强化】第四章 指令系统 4.2 指令寻址方式
    【知识强化】第四章 指令系统 4.1 指令格式
    【知识强化】第三章 存储系统 3.6 高速缓冲存储器
    【知识强化】第三章 存储系统 3.5 双口RAM和多模块存储器
  • 原文地址:https://www.cnblogs.com/xuezou/p/9276945.html
Copyright © 2011-2022 走看看