抽象数据类型

一、概念

  • 表 List【接口】:由数据元素 A1、A2、A3…An,N 个元素构成的序列(有序集合),数据元素之间有前驱后继的关系,大小为0的特殊表称为空表

  • 表的实现

      - 可增长数组的实现:数组一旦创建就不可变,固定容量,内存空间连续,支持索引访问
      	- Vector:线程安全,可以指定增量因子,默认为原来的2倍
      	- ArrayList :线程不安全,不可指定增量因子,默认为原来的1.5倍
      - 双链表的实现:需要时才分配空间,内存空间不连续,不容易索引访问
      	- LinkedList
    
  • 对比 ArrayList & LinkedList

      - ArrayList  的索引访问花费常数时间,插入和删除花费线性时间
      - LinkedList 不容易做索引,索引花费线性时间,而插入和删除花费常数时间
    
  • 栈 ADT :栈也是表,LIFO 后进先出,限制插入和删除只能在表的末端进行

  • 队列 ADT:队列也是表,FIFO 先进先出,插入在表的末端进行,删除在表的开头进行

  • 树:一些节点的集合,集合可以是空集;若不是空集,则树由一个根节点root 和 0 个或多个子树构成,除了root,其余节点都有一条连结父节点的边

      - 根节点:没有父节点的节点
      - 父节点
      - 子节点
      - 叶子节点:没有子节点的节点
      - 兄弟节点:具有相同父节点的节点
      - 路径:任意节点到根节点有且仅有唯一的一条路径【边构成的集合】
      - 深度:根节点的深度为0,任意节点的深度为该节点到 root 节点的边的数量
      - 树的深度:叶子节点中最大的深度
      - 高度:叶子节点的高度为0,任意节点的高度为该节点到叶子节点的边的数量的最大值,树的高度即为根节点的高度
      - n 个节点,存在 n-1 条边
    
    • 二叉树 binary tree:任意节点子树的个数不超过 2

        - 完全二叉树 ::基于数组实现,性能好
        	- 只有最下面的两层节点的子树个数小于2,并且最下面一层的节点都集中在该层最左边的若干位置的二叉树,节点个数连续
        	
        - 满二叉树 ::基于数组实现,性能好
        	- 每一层节点的数量满足 2^n [n 为深度,n>=0]
        	- 深度为 n 的层,节点个数为 2^n [n 为深度,n>=0]
        	- 节点总数  2^n - 1 [n 为层数,n>=1]
      
      • 二叉搜索树 BST

          - 是一颗二叉树
          - 可以比较大小
          - 左子树都小于根节点
          - 右子树都大于根节点
          - 最小值:最左边的叶子节点
          - 最大值:最右边的叶子节点
        
    • 二叉树的遍历

        - 先序遍历:根 -> 左 -> 右
        - 中序遍历:左 -> 根 -> 右
        - 后序遍历:左 -> 右 -> 根
        - 层序遍历:第一层 -> 第二层 -> 第三层 -> ...
      
  • 数据类型:一组值和一组对这些值的操作的集合

  • 抽象数据类型 ADT:一种能够对使用者隐藏内部数据表示的数据类型

  • 对象:能够承载数据类型的值的实体,只要包含3个特性👇

      - 状态:数据类型中的值
      - 标识:在内存中的位置
      - 行为:数据类型的操作
    
  • 当实例调用 new()

      - 为新的对象分配内存空间
      - 调用构造函数初始化对象中的值
      - **返回**该对象的一个**引用**
    
  • 面向数据类的抽象数据类型的主要作用:通过封装数据的表示简化数据的组织和处理

  • 集合类的抽象数据类型的只要作用:简化对同一类型的一组数据的操作

  • API:将使用和实现分离,以实现模块化编程

  • 封装:简化实现和隔离用例开发,实现了模块化编程,将修改代码的影响限制在局部区域,改进了软件的质量,促进了代码复用

  • 继承:不需要重写整个类就能改变它的行为或者为它添加新的功能,有效的重用代码,但会破坏封装性,事实上,子类完全依赖于父类,子类代码可以访问父类的所有实例变量,因此可能会扭曲父类代码的意图

二、抽象数据类型ADT的实现

1、基于数组实现的线性表 ArrayList

// 接口
public interface IList {
	
	void add(int e);
	
	void add(int index,int e);
	
	int get(int index);
	
	int remove();
	
	int remove(int index);
	
	boolean isEmpty();
	
	void clear();
	
	int size();
	
}
/**
 * ADT 抽象数据类型:
 * 1)数据
 * 2)数据操作
 * 
 * 基于数组实现的线性表
 */
public class NArrayList implements IList{
	
	/**
	 * 数据:数组一旦创建,长度不可变,内存空间连续
	 */
	private int[] data;
	
	/**
	 * 大小:当前元素的个数
	 */
	private int size;
	
	/**
	 * 创建列表(线性表),初始容量为 10
	 */
	public NArrayList() {
		this(10);
	}
	
	/**
	 * 创建列表
	 * 
	 * @param capacity 初始容量
	 */
	public NArrayList(int capacity) {
		data = new int[capacity];
		size = 0;
	}


	// 时间复杂度 O(1) 常数级
	@Override
	public void add(int e) {
		if(size==data.length)
			// 扩容
			grow();
		
		// 添加
		data[size] = e;
		size++;
	}

	/**
	 * 扩容
	 * 时间复杂度:O(n) 线性级
	 */
	private void grow() {
		// 数组大小
		int oldLength = data.length;
		// 数组的增量
		// Vector, 变成原来的2倍
		// ArrayList, 变成原来的1.5倍
		int increment = oldLength >> 1;
		// 新的容量
		int newLength = oldLength + increment;
		// 创建一个新数组
		int[] tmp = new int[newLength];
		// 将原数组中的数据存入新数组
		for(int i=0;i<data.length;i++) {
			tmp[i] = data[i];
		}
		// 赋值
		data = tmp;
		System.out.printf("扩容:%d --> %d\n",oldLength,newLength);
	}

	// 时间复杂度 :复杂度 线性级 O(n)
	@Override
	public void add(int index, int e) {

		if(data.length==size)
			grow();
		if(index>size)
			throw new ArrayIndexOutOfBoundsException(index);
		
		// 移动
		int last = size-1;
		for(int i=last;i>=index;i--) {
			data[i+1] = data [i];
		}
		data[index] = e;
		size++;
	}

	/**
	 * 取index位置元素
	 * 时间复杂度 O(1) 常数级
	 */
	@Override
	public int get(int index) {
		if(index<0 || index >=size)
			throw new ArrayIndexOutOfBoundsException(index);
		return data[index];
	}

	/**
	 * 删除最后一个
	 * 时间复杂度 O(1) 常数级
	 */
	@Override
	public int remove() {
		if(isEmpty())
			throw new ArrayIndexOutOfBoundsException();
		// 删除最后一个并返回
		return data[--size];
	}

	/**
	 * 删除index位置
	 * 时间复杂度:O(n) 线性级
	 */
	@Override
	public int remove(int index) {
		
		if(index<0 || index>=size) {
			throw new ArrayIndexOutOfBoundsException(index);
		}
		int tmp = data[index];
		// index + 1 ~ size - 1 ,都往前移动一位
		for(int i=index+1;i<size;i++) {
			data[i-1] = data[i];
		}
		size--;
		return tmp;
		
	}

	/**
	 * 数组是否为空
	 */
	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 清空数组
	 */
	@Override
	public void clear() {
		size = 0;
	}

	@Override
	public int size() {
		return size;
	}
}

2、双向链表的实现 LinkedList

/**
 * 节点
 */
public class Node {

	/**
	 * 元素
	 */
	int element;
	
	/*
	 * 前驱
	 */
	Node prev;
	
	/*
	 * 后继
	 */
	Node next;
	
	/**
	 * 创建一个节点
	 */
	public Node() {
	}

	/**
	 * 创建一个新节点
	 * 
	 * @param element 元素
	 * @param prev 	  前驱节点
	 * @param next    后继节点
	 */
	public Node(int element, Node prev, Node next) {
		super();
		this.element = element;
		this.prev = prev;
		this.next = next;
	}
}

/**
 * 双向 链表
 */
public class NLinkedList implements IList {

	/**
	 * 大小
	 */
	int size;

	/**
	 * 头指针
	 */
	Node head;

	/**
	 * 尾指针
	 */
	Node tail;

	/**
	 * 构造函数
	 */
	public NLinkedList() {
		// 头节点无前驱
		head = new Node();
		// 尾节点无后继
		tail = new Node();

		// 一开始首尾相连
		head.next = tail;
		tail.prev = head;
	}

	/**
	 * 在尾部添加新节点 
	 * 时间复杂度: 常数级 O(1)
	 */
	@Override
	public void add(int e) {
		// 插入末尾,即尾指针的前一个结点,后继是尾节点,尾节点的前驱是新节点的前驱
		Node node = new Node(e, tail.prev, tail);

		// 尾节点的前驱节点的后继是新节点
		tail.prev.next = node;
		// 尾节点的前驱是新节点
		tail.prev = node;

		size++;
	}

	/**
	 * 链表的插入和删除的时间复杂度都是 常数级 O(1)
	 * 在 index 位置插入新节点
	 */
	@Override
	public void add(int index, int e) {
		// 如果插入的是末尾
		if (index == size) {
			add(e);
		} 
		else {
			// 获得索引位置节点
			Node target = getNode(index);
			// 创建一个新节点,前驱为目标节点的前驱,后驱为目标节点
			Node node = new Node(e, target.prev, target);
			// 目标节点前驱的后继为新节点
			target.prev.next = node;
			// 目标节点的前驱为新节点
			target.prev = node;

			size++;
		}
	}

	/**
	 * 获得索引位置节点 时间复杂度O(n)
	 * 
	 * @param index 索引
	 * @return 目标节点
	 */
	private Node getNode(int index) {
		if (index < 0 || index >= size)
			throw new ArrayIndexOutOfBoundsException();

		// 1、从前往后找
		// 从头针指开始
		Node node = head;
		for (int i = 0; i <= index; i++) {
			node = node.next;
		}

		// 2、从后往前找
		// TODO

		return node;
	}

	/**
	 * 返回index位置的节点数据
	 */
	@Override
	public int get(int index) {
		return getNode(index).element;
	}

	/**
	 * 删除最后一个节点,即尾指针的前一个节点
	 */
	@Override
	public int remove() {
		if (isEmpty())
			throw new ArrayIndexOutOfBoundsException();

		// 最后一个节点
		Node node = tail.prev;

		// 尾指针成为被删节点的前驱的后继
		node.prev.next = tail;
		// 被删节点的前驱成为尾指针的前驱
		tail.prev = node.prev;

		size--;
		// 返回被删节点的数值
		return node.element;

	}

	/**
	 * 删除index位置的节点
	 */
	@Override
	public int remove(int index) {
		if (index < 0 || index >= size)
			throw new ArrayIndexOutOfBoundsException(index);

		// 目标节点
		Node node = getNode(index);

		node.next.prev = node.prev;
		node.prev.next = node.next;
		size--;

		return node.element;
	}

	/**
	 * 判断是否为空
	 */
	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 清空链表
	 */
	@Override
	public void clear() {
		// 首尾相连
		head.next = tail;
		tail.prev = head;

		size = 0;
	}

	/**
	 * 链表大小
	 */
	@Override
	public int size() {
		return size;
	}

}

3、基于数组实现的栈 Stack

// 接口
public interface IStack {

	/**
	 * 压栈
	 * 
	 * @param e
	 * @return
	 */
	int push(int e);
	
	/**
	 * 读取栈顶元素
	 * 
	 * @return
	 */
	int peek();
	
	/**
	 * 出栈
	 * 
	 * @return
	 */
	int pop();
	
	/**
	 * 大小
	 * 
	 * @return
	 */
	int size();
	
	/**
	 * 栈是否为空
	 * 
	 * @return
	 */
	boolean isEmpty();
	
	/**
	 * 清空
	 */
	void clear();
}

/**
 * 基于 数组 实现的 栈
 *
 */
public class NStack implements IStack {

	/**
	 * 数据
	 */
	private int[] data;

	/**
	 * 栈顶标识
	 */
	private int top = -1;

	public NStack() {
		data = new int[10];
	}

	/**
	 * 压栈
	 */
	@Override
	public int push(int e) {
		if (data.length == top + 1)
			grow();

		data[++top] = e;
		return e;
	}

	/**
	 * 扩容
	 */
	private void grow() {
		// 数组大小
		int oldLength = data.length;
		// 数组的增量
		// Vector, 变成原来的2倍
		// ArrayList, 变成原来的1.5倍
		int increment = oldLength >> 1;
		// 新的容量
		int newLength = oldLength + increment;
		// 创建一个新数组
		int[] tmp = new int[newLength];
		// 将原数组中的数据存入新数组
		for (int i = 0; i < data.length; i++) {
			tmp[i] = data[i];
		}
		// 赋值
		data = tmp;
	}

	/**
	 * 读取栈顶元素
	 */
	@Override
	public int peek() {
		if (isEmpty())
			throw new EmptyStackException();

		return data[top];
	}

	/**
	 * 出栈
	 */
	@Override
	public int pop() {
		if (isEmpty())
			throw new EmptyStackException();

		return data[top--];
	}

	/**
	 * 元素个数
	 */
	@Override
	public int size() {
		return top + 1;
	}

	/**
	 * 栈是否为空
	 */
	@Override
	public boolean isEmpty() {
		return top == -1;
	}

	/**
	 * 清空
	 */
	@Override
	public void clear() {
		top = -1;
	}

	@Override
	public String toString() {
		
		StringBuilder sb = new StringBuilder("[");
		for (int i=0;i<=top;i++) {
			sb.append(data[i]+",");
		}
		sb.deleteCharAt(sb.length()-1);
		sb.append("]");
		return sb.toString();
	}
}

4、基于链表实现的栈 Stack

/**
 * 基于 链表 实现的 栈
 *
 */
public class NStack implements IStack {

	// 栈顶标识
	Node top;
	
	// 大小
	int size = 0;

	public NStack() {
		top = new Node();
	}

	@Override
	public int push(int e) {
		Node node = new Node(e, top, top.next);
		top = node;
		size++;
		return e;
	}

	@Override
	public int poll() {
		if (isEmpty())
			throw new EmptyStackException();
		int e = top.element;
		top = top.prev;
		top.next = null;
		size--;
		return e;
	}

	@Override
	public int peek() {
		if (isEmpty())
			throw new EmptyStackException();

		return top.element;
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public void clear() {
		size = 0;
	}

	// Node 内部类
	private static class Node {

		int element;
		Node prev;
		Node next;
		
		public Node() {
		}
		
		public Node(int element, Node prev, Node next) {
			super();
			this.element = element;
			this.prev = prev;
			this.next = next;
		}
	}
	
}

5、基于数组实现的队列 ArrayDeque

// 接口
public interface IQueue {

	/**
	 * 入队
	 * @param e
	 */
	void offer(int e);
	
	/**
	 * 读取
	 * @return
	 */
	int peek();
	
	/**
	 * 轮询 epoll
	 * @return
	 */
	int poll();
	
	int size();
	
	void clear();
	
	boolean isEmpty();
}

/**
 * 基于 数组 实现的 队列
 */
public class NQueue implements IQueue {

	/**
	 * 数据元素
	 */
	int[] data;

	/**
	 * 头指针
	 */
	int head = 0;

	/**
	 * 尾指针
	 */
	int tail = 0;

	public NQueue() {
		data = new int[10];
	}

	// 操作
	@Override
	public void offer(int e) {
		if (data.length == tail + 1)
			grow();
		data[tail++] = e;
	}

	/*
	 * 扩容
	 */
	private void grow() {
		// 数组大小
		int oldLength = data.length;
		// 数组的增量
		// Vector, 变成原来的2倍
		// ArrayList, 变成原来的1.5倍
		int increment = oldLength >> 1;
		// 新的容量
		int newLength = oldLength + increment;
		// 创建一个新数组
		int[] tmp = new int[newLength];
		// 将原数组中的数据存入新数组
		for (int i = 0; i < data.length; i++) {
			tmp[i] = data[i];
		}
		// 赋值
		data = tmp;
	}

	@Override
	public int peek() {
		if (isEmpty())
			throw new EmptyStackException();
		return data[head];
	}

	@Override
	public int poll() {
		if (isEmpty())
			throw new EmptyStackException();
		return data[head++];
	}

	@Override
	public int size() {
		return tail - head;
	}

	@Override
	public void clear() {
		head = tail = 0;
	}

	@Override
	public boolean isEmpty() {
		return head == tail;
	}

	@Override
	public String toString() {

		StringBuilder sb = new StringBuilder("[");
		for (int i = head; i < tail; i++) {
			sb.append(data[i] + ",");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append("]");
		return sb.toString();
	}
}

6、基于链表实现的队列 LinkedList

/**
 * 基于链表实现的队列
 *
 */
public class NQueue implements IQueue{
	
	// 头标识
	Node head;
	
	// 尾标识
	Node tail;
	
	//大小
	int size = 0;

	public NQueue() {
		head = new Node();
		tail = new Node();
		head.next = tail;
		tail.prev = head;
	}
	
	@Override
	public void offer(int e) {
		Node node = new Node(e,tail.prev,tail);
		tail.prev.next = node;
		tail.prev = node;
		size++;
	}

	@Override
	public int peek() {
		if(isEmpty())
			throw new EmptyStackException();

		return head.next.element;
	}

	@Override
	public int poll() {
		if(isEmpty())
			throw new EmptyStackException();
		int e = head.next.element;
		head.next.next.prev = head;
		head.next = head.next.next;
		size--;
		return e;
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public void clear() {
		size = 0;
		head.next = tail;
		tail.prev = head;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}
	

	// Node 内部类
	private static class Node{
		
		int element;
		Node prev;
		Node next;
		
		public Node() {
		}
		
		public Node(int element, Node prev, Node next) {
			super();
			this.element = element;
			this.prev = prev;
			this.next = next;
		}
		
	}
}


7、二叉搜索树 Binary Search Tree ADT

/**
 * 二叉树的节点
 */
public class Node {
	
	/**
	 * 值
	 */
	int value;
	
	/**
	 * 左子树
	 */
	Node left;

	/**
	 * 右子树
	 */
	Node right;
	
	public Node() {
	}
	
	public Node(int value, Node left, Node right) {
		super();
		this.value = value;
		this.left = left;
		this.right = right;
	}
	
	@Override
	public String toString() {
		return String.valueOf(value);
	}
	
}

// 接口
public interface ITree {

	// 添加
	Node put(int e);
	
	// 删除
	Node remove(int e);
	
	// 先序遍历
	void preOrder();
	
	// 中序遍历
	void midOrder();
	
	// 后序遍历
	void postOrder();
	
	// 层序遍历
	void order();
	
	// 最大值
	int findMax();
	
	// 最小值
	int findMin();
	
	//大小
	int size();
	
	// 清空
	void clear();
	
	// 判断是否为空
	boolean isEmpty();
	
	// 反转
	void reverse();
}
/**
 * 二叉搜索树 :: 基于数组实现
 *  BST
 */
public class Tree implements ITree{

	// 数据
	
	/**
	 * 根节点
	 */
	Node root;
	
	/**
	 * 大小
	 */
	int size;
	
	/**
	 * 构造函数
	 * 初始化树
	 */
	public Tree() {
		root = null;
		size = 0;
	}
	
	// 操作
	
	/**
	 * 插入一个新节点
	 * @param e 新元素的值
	 * @return 新节点
	 */
	@Override
	public Node put(int e) {
		if (root==null) {
			root = put(e,root);
		}
		return put(e,root);
	}
	/**
	 * 从特定节点插入新节点
	 * @param e 新元素的值
	 * @param node 起始位置
	 * @return 新节点
	 */
	private Node put(int e, Node node) {
		if (node==null) {
			// 如果 树空
			node = new Node(e,null,null);
			size++;
		} else {
			if (e<node.value) {
				// 递归插入左子树
				node.left = put(e,node.left);
			} else if(e>node.value){
				// 递归插入右子树
				node.right = put(e,node.right);
			}else {
				// e 存在,不处理	
			}
		}
		return node;
	}
	
	/**
	 * 大小
	 */
	@Override
	public int size() {
		return size;
	}

	/**
	 * 清空
	 */
	@Override
	public void clear() {
		root = null;
		size = 0;
	}

	/**
	 * 是否为空树
	 */
	@Override
	public boolean isEmpty() {
		return root == null;
	}

	/**
	 * 找最大值
	 */
	@Override
	public int findMax() {
		return findMax(root).value;
	}
	private Node findMax(Node node) {
		// 1.递归实现
		if(node==null)
			return null;

		return node.right==null ? node:findMax(node.right);
		
		// 2.循环实现
//		if(node==null)
//			return null;
//		while(node.right!=null) {
//			node = node.right;
//		}
//		return node;
	}

	/**
	 * 找最小值
	 */
	@Override
	public int findMin() {
		return findMin(root).value;
	}
	private Node findMin(Node node) {
		// 1.递归实现
		if(node==null)
			return null;
		
		return node.left==null ? node:findMin(node.left);
		
		// 2.循环实现
//		if(node==null)
//			return null;
//		while(node.left!=null) {
//			node = node.left;
//		}
//		return node;
		
	}

	/**
	 * 先序遍历
	 */
	@Override
	public void preOrder() {
		preOrder(root);
	}
	// 根 -> 左 -> 右
	private void preOrder(Node node) {
		if(node==null)
			return;
		// 输出根节点的值
		System.out.print(node.value+" ");
		// 遍历左子树
		preOrder(node.left);
		// 遍历右子树
		preOrder(node.right);
	}

	/**
	 * 中序遍历
	 */
	@Override
	public void midOrder() {
		midOrder(root);
	}
	// 左 -> 根 -> 右
	private void midOrder(Node node) {
		if(node==null)
			return;
		// 遍历左子树
		midOrder(node.left);
		// 输出根节点的值
		System.out.print(node.value+" ");
		// 遍历右子树
		midOrder(node.right);
	}

	/**
	 * 后序遍历
	 */
	@Override
	public void postOrder() {
		postOrder(root);
	}
	// 左 -> 右 -> 根
	private void postOrder(Node node) {
		if(node==null)
			return;
		postOrder(node.left);
		postOrder(node.right);
		System.out.print(node.value+" ");
	}

	/**
	 * 层序遍历
	 */
	@Override
	public void order() {
		if(root==null)
			return;
		Queue<Node> queue = new LinkedList<>();
		queue.add(root);
		while(!queue.isEmpty()) {
			Node node = queue.poll();
			System.out.print(node.value+" ");
			if(node.left!=null) {
				queue.add(node.left);
			}
			if(node.right!=null) {
				queue.add(node.right);
			}
		}
	}

	/**
	 * 翻转/镜像
	 */
	@Override
	public void reverse() {
		reverse(root);
	}
	private void reverse(Node node) {
		if(node==null)
			return;
		if((node.left == null) && (node.right == null))
            return;
		Node tmp = node.left;
		node.left = node.right;
		node.right = tmp;
		reverse(node.left);
		reverse(node.right);
	}

	/**
	 * 删除节点
	 */
	@Override
	public Node remove(int value) {
		if(root==null)
			throw null;
		return remove(value,root);
	}
	private Node remove(int value, Node node) {
		if(value<node.value)
			node.left = remove(value, node.left);
		else if(value>node.value)
			node.right = remove(value, node.right);
		else if(node.left!=null&&node.right!=null) {
			// 找到右子树中最小的节点替换被删节点
			node.value = findMin(node.right).value;
			node.right = remove(node.value,node.right);
		}else {
			node =(node.left!=null) ? node.left : node.right;
		}
		return node;
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值