Java数据结构与算法(1):线性表
线性表是一种简单的数据类型,它是具有相同类型的n个数据元素组成的有限序列。形如如A0,A1,...,An-1。大小为0的表为空表,称Ai后继Ai-1,并称Ai-1前驱Ai。
printList打印出表元素,makeEmpty置空表,find返回某一项首次出现的位置,insert和remove一般是从表的某个位置插入和删除某个元素;而findKth则返回某个位置上的元素,next和previous会取一个位置作为参数返回前驱元和后继元的值。
表的数组实现
对表的所有操作都可以通过数组实现。数组的存储示意图如下:

这种存储结构的特点是:数据是连续的,随机访问速度快。printList以线性时间执行,findKth操作则话费常数时间。对于插入和删除来说效率是比较低下的,最坏情况下,在位置0的插入需要将所有元素向后移动一个位置。
基于数组的链表实现:
public class MyArrayList<T> implements Iterable<T>{
private static final int DEFAULT_CAPACITY=10;
private int size;
private T[] items;
public MyArrayList() {
doClear();
}
public void clear() {
doClear();
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void trimToSize() {
ensureCapacity(size);
}
public boolean add(T x) {
add(size, x);
return true;
}
public void add(int idx, T x) {
if (items.length == size) {
ensureCapacity(size * 2 + 1);
}
for (int i = size; i > idx; i--) {
items[i] = items[i - 1];
}
items[idx] = x;
size++;
}
public T remove(int idx) {
T removedItem = items[idx];
for (int i = idx; i < size - 1; i++) {
items[i] = items[i + 1];
}
size--;
return removedItem;
}
private void doClear() {
size = 10;
ensureCapacity(DEFAULT_CAPACITY);
}
private void ensureCapacity(int newCapacity) {
if (newCapacity < size) {
return;
}
T[] old = items;
items = (T[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
items[i] = old[i];
}
}
public Iterator<T> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator<T> {
private int current = 0;
@Override
public boolean hasNext() {
return current < size;
}
@Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
return items[current++];
}
public void remove() {
MyArrayList.this.remove(--current);
}
}
}
单链表
当需要对表进行频繁的插入删除操作时,数组的实现方式就显得效率过低了。链表由一些列节点组成,这些节点不必在内存中相连。每一个节点均含有表元素和到包含该元素后继元的节点的链。单链表的存储示意图如下:

remove操作只需要移动next引用即可实现:

insert方法需要先添加一个节点,然后执行两次引用的调整:

单链表的特点:节点的链接方向是单向的;相对于数组,单链表的随机访问速度较慢,添加、删除效率较高。
双向链表
双向链表与单向链表结构相似,由数据元素和两个链组成,这两个链分别指向该节点的前驱和后继。一般构建为双向循环链表,即最后一个节点的next链指向链表的第一个元素,第一个节点的previous链指向链表的最后一个元素。存储结构如下:

双向链表删除:

双向链表的添加就是删除的一个逆过程,不再画图了。
双向链表实现:
public class DoubleLink<T> {
// 表头
private Node<T> head;
// 节点数
private int count;
private class Node<T> {
public Node prev; // 前节点
public Node next; // 后节点
public T value;
public Node(T value, Node prev, Node next) {
this.prev = prev;
this.next = next;
this.value = value;
}
}
public DoubleLink() {
// 创建表头
head = new Node<>(null, null, null);
head.prev = head.next = head;
count = 0;
}
// 节点数
public int size() {
return count;
}
// 判断表是否为空
public boolean isEmpty() {
return count == 0;
}
// 获取第index位置的节点
private Node<T> getNode(int index) {
if (index < 0 || index >= count) {
throw new IndexOutOfBoundsException();
}
// 正向查找
if (index <= count / 2) {
Node<T> node = head.next;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
// 反向查找
Node<T> rnode = head.prev;
int rindex = count - index - 1;
for (int j = 0; j < rindex; j++) {
rnode = rnode.prev;
}
return rnode;
}
// 获取第index位置节点的值
public T get(int index) {
return getNode(index).value;
}
// 将节点插入到index位置
public void insert(int index, T t) {
if (index == 0) {
Node node = new Node(t, head, head.next);
head.next.prev = node;
head.next = node;
count++;
return;
}
Node<T> inode = getNode(index);
// 创建新节点
Node<T> newNode = new Node<>(t, inode.prev, inode);
inode.prev.next = newNode;
inode.next = newNode;
return;
}
// 删除节点
public Node<T> delete(int index) {
Node<T> delNode = getNode(index);
delNode.prev.next = delNode.next;
delNode.next.prev = delNode.prev;
count--;
return delNode;
}
}
Java数据结构与算法(1):线性表的更多相关文章
- Java数据结构和算法 - 哈希表
Q: 如何快速地存取员工的信息? A: 假设现在要写一个程序,存取一个公司的员工记录,这个小公司大约有1000个员工,每个员工记录需要1024个字节的存储空间,因此整个数据库的大小约为1MB.一般的计 ...
- 【数据结构与算法】线性表操作(C++)
#include <stdio.h> #define maxSize 100 //定义整型常量maxSize值为100 /*顺序表的结构体定义*/ typedef struct SqLis ...
- 【数据结构与算法】线性表操作(C语言)
#include <stdio.h> #include <stdlib.h> #define OK 1 #define NO 0 #define MAXSIZE 20 type ...
- Java数据结构和算法(一)线性结构
Java数据结构和算法(一)线性结构 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 线性表 是一种逻辑结构,相同数据类型的 ...
- Java数据结构和算法(一)线性结构之单链表
Java数据结构和算法(一)线性结构之单链表 prev current next -------------- -------------- -------------- | value | next ...
- 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现
本篇是java数据结构与算法的第2篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 顺序栈的设计与实现 链式栈的设计与实现 栈的应用 栈的抽象数据类型 栈是 ...
- java数据结构与算法之栈(Stack)设计与实现
本篇是java数据结构与算法的第4篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 顺序栈的设计与实现 链式栈的设计与实现 栈的应用 栈的抽象数据类型 栈是一种用于 ...
- Java数据结构和算法 - 高级排序
希尔排序 Q: 什么是希尔排序? A: 希尔排序因计算机科学家Donald L.Shell而得名,他在1959年发现了希尔排序算法. A: 希尔排序基于插入排序,但是增加了一个新的特性,大大地提高了插 ...
- Java数据结构和算法(一)散列表
Java数据结构和算法(一)散列表 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 散列表(Hash table) 也叫哈希表 ...
随机推荐
- Springboot2.x集成Redis哨兵模式
Springboot2.x集成Redis哨兵模式 说明 Redis哨兵模式是Redis高可用方案的一种实现方式,通过哨兵来自动实现故障转移,从而保证高可用. 准备条件 pom.xml中引入相关jar ...
- 首次全备及事务备份对数据库的影响,2014 SpexSql log评估版探索
参考:https://www.cnblogs.com/gered/p/9882367.html 关键词:解析事务日志 新建数据库test3,然后查看日志文件,382行记录 SELECT min([Be ...
- Scrapy 教程(一)-安装与入门
安装 具体请自行百度 依赖库 网上说pip安装会内分泌失调,我试了下还行吧,不过也遇到几个问题 解决方法 pip install -I cryptography 解决方法 pip install -U ...
- Serilog
参考 asp.net core使用serilog将日志推送到腾讯云日志服务
- LeetCode-239-剑指offer-滑动窗口的最大值-队列与栈-python
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值.例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6, ...
- c# wpf 加密文本
可以加密人们的内容,文本加密. 界面 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation& ...
- WPS专业版及序列号
目录 1. 软件下载 2. 序列号(永久) 1. 软件下载 城通网盘:https://sn9.us/dir/13403389-35833830-3fc98f (仅Android版) 官网: https ...
- 使用Medusa美杜莎暴力破解SSH密码
使用Medusa美杜莎暴力破解SSH密码 1.Medusa简介 Medusa(美杜莎)是一个速度快,支持大规模并行,模块化的爆力破解工具.可以同时对多个主机,用户或密码执行强力测试.Medusa和hy ...
- 洛谷 P2622 关灯问题II (状态压缩+BFS)
题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的灯都有一个效果.按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时 ...
- Linux shell 误操作
shell脚本在日常运维中是必不可少会应用到,下面是自己亲身经历过的一件事.会了定期清除日志,编写了一个shell脚本,内容如下: [root@centos- tmp]# more remote_lo ...