抽象数据类型
一、概念
-
表 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;
}
}