【数据结构与算法】第二章 动态数组

什么是数据结构

数据结构是计算机存储、组织数据的方式。
在这里插入图片描述
在实际应用中,根据使用场景来选择最合适的数据结构。

线性表

线性表是具有 n 个相同类型元素的有限序列( n ≥ 0 )

在这里插入图片描述

  • a1 是首节点(首元素),an 是尾结点(尾元素)
  • a1 是 a2 的前驱, a2 是 a1 的后继

常见的线性表有:

  • 数组
  • 链表
  • 队列
  • 哈希表 (散列表)

数组(Array)

数组是一种顺序存储的线性表,所有元素的内存地址是连续的。

在这里插入图片描述
在很多编程语言中,数组都有个致命的缺点:无法动态修改容量
实际开发中,我们更希望数组的容量是可以动态改变的

动态数组(Dynamic Array)接口设计

在这里插入图片描述

动态数组的设计

在这里插入图片描述

在Java中,成员变量会自动初始化,比如

  • int 类型自动初始化为 0
  • 对象类型自动初始化为 null

除上述接口外还需要设置以下属性和方法:

	// 元素的数量
	private int size;
	// 所有元素
	private E[] elements;
	// 数组默认容量大小
	private static final int DEFAULT_CAPACITY = 10;
	// 按索引查找时没有找到数据就返回-1
	private static final int ELEMENT_NOT_FOUND = -1;
	
	// 为数组开辟空间
	public ArrayList(int capacity){
		capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
		elements = (E[]) new Object[capacity];
	}
	
	public ArrayList(){
		this(DEFAULT_CAPACITY);
	}
	
	// 数组下标越界后手动抛出异常
	private void outOfBound(int index){
		throw new ArrayIndexOutOfBoundsException("Index:" + index + ",Size:" + size);
	}
	// 检测数组下标是否越界
	private void rangeCheck(int index){
		if (index < 0 || index >= size){
			outOfBound(index);
		}
	}
	// 特殊情况:检测数组添加元素时下标是否越界
	private void rangeCheckForAdd(int index){
		if (index < 0 || index > size){
			outOfBound(index);
		}
	}

添加元素 - add(E element)

add(E element):将元素添加到最后面

在这里插入图片描述
add(int index, E element):将元素添加到指定位置

在这里插入图片描述
代码实现:

	/**
	 * 往index位置添加元素
	 * @param index
	 * @param element
	 */
	public void add(int index, E element){
		rangeCheckForAdd(index); // 检查数组下标是否越界
		ensureCapacity(size + 1); // 扩容,确保容量够大
		for (int i = size - 1; i >= index; i--) {
			elements[i+1] = elements[i];
		}
		elements[index] = element;
		size++;
	}
	
	/**
	 * 添加元素到最后面
	 * @param element
	 */
	public void add(E element){
		add(size, element);
	}

清除所有元素 - clear()

  • 若为基本数据类型,设置size = 0即可,不需要设置elements = null
  • 使用泛型后要需要将元素置为null

代码实现:

	/**
	 * 清除所有元素
	 */
	public void clear(){
		// 使用泛型后要注意内存管理,要将元素置为null
		for (int i = 0; i < size; i++) {
			elements[i] = null;
		}
		size = 0;
	}

删除元素 - remove(int index)

在这里插入图片描述
最后一个元素需要如何处理:

  • 如果存放 int 类型,size-- 后,最后一个元素已经无法访问了。
  • 使用泛型后要注意内存管理,要将元素置为null。

代码实现:

	/**
	 * 删除index位置对应的元素
	 * @param index
	 * @return
	 */
	public E remove(int index){
		rangeCheck(index);
		E old = elements[index];
		for (int i = index + 1; i <= size - 1; i++) {
			elements[i -1] = elements[i];
		}

		elements[--size] = null;
		return old;
	}

打印数组

  • 重写 toString 方法
  • 在 toString 方法中将元素拼接成字符串
  • 字符串拼接建议使用 StringBuilder

代码实现:

	@Override
	public String toString() {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("size = ").append(size).append(", ["); 
		for (int i = 0; i < size; i++) {
			if (i != 0) {
				stringBuffer.append(", ");
			}
			stringBuffer.append(elements[i]);
		}
		stringBuffer.append("]");
		return stringBuffer.toString();
	}

查找元素

	/**
	 * 是否包含某个元素
	 * @param element
	 * @return
	 */
	public boolean contains(E element){
		return indexOf(element) != ELEMENT_NOT_FOUND;
	}

	/**
	 * 返回index位置对应的元素
	 * @param index
	 * @return
	 */
	public E get(int index){
		rangeCheck(index);
		return elements[index];
	}

	/**
	 * 查看元素的位置
	 * @param element
	 * @return
	 */
	public int indexOf(E element){
		if(element == null){
			for (int i = 0; i < size; i++) {
				if(elements[i] == null) return i;
			}
		}else {
			for (int i = 0; i < size; i++) {
				if(element.equals(elements[i])) return i;
			}
		}
		
		return ELEMENT_NOT_FOUND; 
	}

扩容

在这里插入图片描述
代码实现:

	// 扩容操作
	private void ensureCapacity(int capacity){
		int oldCapacity = elements.length;
		if(oldCapacity >= capacity) return;
		
		// 新容量为旧容量的1.5倍
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		E[] newElements = (E[]) new Object[newCapacity];
		for (int i = 0; i < size; i++) {
			newElements[i] = elements[i];
		}
		
		elements = newElements;
	}

对象数组

Object数组中存放的是对象的引用地址

在这里插入图片描述

泛型动态数组源码(Java版)

public class ArrayList<E> {
	// 元素的数量
	private int size;
	// 所有元素
	private E[] elements;
	// 数组默认容量大小
	private static final int DEFAULT_CAPACITY = 2;
	private static final int ELEMENT_NOT_FOUND = -1;
	
	public ArrayList(int capacity){
		capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
		elements = (E[]) new Object[capacity];
	}
	
	public ArrayList(){
		this(DEFAULT_CAPACITY);
	}
	
	private void outOfBound(int index){
		throw new ArrayIndexOutOfBoundsException("Index:" + index + ",Size:" + size);
	}
	
	private void rangeCheck(int index){
		if (index < 0 || index >= size){
			outOfBound(index);
		}
	}
	
	private void rangeCheckForAdd(int index){
		if (index < 0 || index > size){
			outOfBound(index);
		}
	}
	
	private void ensureCapacity(int capacity){
		int oldCapacity = elements.length;
		if(oldCapacity >= capacity) return;
		
		// 新容量为旧容量的1.5倍
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		E[] newElements = (E[]) new Object[newCapacity];
		for (int i = 0; i < size; i++) {
			newElements[i] = elements[i];
		}
		
		elements = newElements;
	}
	
	/**
	 * 元素的数量
	 * @return
	 */
	public int size(){
		return size;
	}  
	
	/**
	 * 是否为空
	 * @return
	 */
	public boolean isEmpty(){
		return size == 0;
	} 
	
	/**
	 * 是否包含某个元素
	 * @param element
	 * @return
	 */
	public boolean contains(E element){
		return indexOf(element) != ELEMENT_NOT_FOUND;
	}
	
	/**
	 * 添加元素到最后面
	 * @param element
	 */
	public void add(E element){
		add(size, element);
	}
	
	/**
	 * 返回index位置对应的元素
	 * @param index
	 * @return
	 */
	public E get(int index){
		rangeCheck(index);
		return elements[index];
	}
	
	/**
	 * 设置index位置的元素
	 * @param index
	 * @param element
	 * @return
	 */
	public E set(int index, E element){
		rangeCheck(index);
		E old = elements[index];
		elements[index] = element;
		return old;
	}
	
	/**
	 * 往index位置添加元素
	 * @param index
	 * @param element
	 */
	public void add(int index, E element){
		rangeCheckForAdd(index);
		ensureCapacity(size + 1);
		for (int i = size - 1; i >= index; i--) {
			elements[i+1] = elements[i];
		}
		elements[index] = element;
		size++;
	}
	
	/**
	 * 删除index位置对应的元素
	 * @param index
	 * @return
	 */
	public E remove(int index){
		rangeCheck(index);
		E old = elements[index];
		for (int i = index + 1; i <= size - 1; i++) {
			elements[i -1] = elements[i];
		}

		elements[--size] = null;
		return old;
	}
	
	/**
	 * 查看元素的位置
	 * @param element
	 * @return
	 */
	public int indexOf(E element){
		if(element == null){
			for (int i = 0; i < size; i++) {
				if(elements[i] == null) return i;
			}
		}else {
			for (int i = 0; i < size; i++) {
				if(element.equals(elements[i])) return i;
			}
		}
		
		return ELEMENT_NOT_FOUND; 
	}
	
	/**
	 * 清除所有元素
	 */
	public void clear(){
		for (int i = 0; i < size; i++) {
			elements[i] = null;
		}
		size = 0;
	}

	@Override
	public String toString() {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append("size = ").append(size).append(", ["); 
		for (int i = 0; i < size; i++) {
			if (i != 0) {
				stringBuffer.append(", ");
			}
			stringBuffer.append(elements[i]);
		}
		stringBuffer.append("]");
		return stringBuffer.toString();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值