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) 也叫哈希表 ...
随机推荐
- 标准库path源码解读
先看标准库 作用:关于路径的一些实用操作 https://github.com/golang/go/blob/master/src/path/path.go 源码地址 func IsAbs func ...
- [七月挑选]使用hexo建立主题,并发布到github
title: 使用hexo建立主题,并发布到github 根据hexo官网的概述和hexo官网的建站,搭建最开始的hexo博客. 1.环境预先安装好node.js和git 2.npm安装hexo: $ ...
- 为啥要使用Hessian
1.为啥要使用Hessian? 有需求就有市场,挨踢界也是一样,想要实现远程调用,Hessian就应运而生. 场景:有一个后台系统,基本上所有的用户管理都在这个系统里操作,其中有一个方法是添加用户的方 ...
- How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained
http://blog.originate.com/blog/2014/02/20/afimagecache-vs-nsurlcache/
- Django之modles 多对多创建第三张表
一.第一种:纯自动创建第三张表 纯自动 class Book(models.Model): title = models.CharField(max_length=32) price = models ...
- Git Fast Forward 和 no fast foward
如果执行了 Fast Forward,开发者根本不会看到这个分支,就像在 master 直接 commit 一样.
- IDEA开发初始化设置
一.基本设置 1. 自动生成 serialVersionUID 的设置 2. 设置文件注释 3. 隐藏项目文件(夹) .git;.gitignore;.idea;.idea/.;.mvn;mvnw;m ...
- springcloud 配置actuator
pom.xml <!--Spring Boot Actuator,感应服务端变化--> <dependency> <groupId>org.springframew ...
- RAC heartbeat 心跳机制
世界上最遥远的距离,不是生与死.而是我们同一个集群的两个节点,你却听不到我的心跳. 必要性:维持集群的⼀致性RAC⼼跳机制 – 集群⼼跳基本机制:1.确定节点和节点间的连通性,达到彼此了解2.⽤共享的 ...
- wepy-开发总结(功能点)
开发小程序中,遇到的wepy的几点坑,记录一下; 更详细的项目总结记录请见我的个人博客:https://fanghongliang.github.io/ 1.定时器: 在页面中有需要用到倒计时或者其他 ...