数据结构、算法
1、基础概念
-
数据结构(Data Structure):存储数据的不同方式
-
算法(Algorithm):同一个问题的不同的解决方法;算法往往是针对特定数据结构的
-
如何测算算法的优劣
- 时间测算:估算程序指令的执行次数(执行时间)
- 计算算法时间差
- 幅度不够循环来凑
- 空间测算:估算所需占用的存储空间
- 时间测算:估算程序指令的执行次数(执行时间)
-
Big O----更多关注时间复杂度
- 时间-问题(数据)规模
- 不考虑必须要做的操作
- 循环、赋初值、程序初始化
- 不考虑常数项、系数
- 9 >> O(1)、2n + 3 >> O(n)
- 不考虑低次项、低阶
- n^2 + 2n + 6 >> O(n^2)
- 4n^3 + 3n^2 + 22n + 100 >> O(n^3)
- 对数阶一般省略底数
- 不考虑必须要做的操作
- 时间-问题(数据)规模
-
多个数据规模的情况
- 空间复杂度
- 看看执行代码,需要多大的存储空间
- 看看执行代码,需要多大的存储空间
- 空间复杂度
-
算法的优化方向
- 用尽量少的存储空间
- 用尽量少 的执行步骤(执行时间)
- 根据情况
- 空间换时间
- 时间换空间
- 如何写算法程序
- 验证算法----对数器
2、数据结构
2.1 线性表
2.1.1 数组
- 数组是一种顺序存储的线性表,所有元素的内存地址是连续的
- 无法动态修改容量
- 时间复杂度
- 经过连续的多次复杂度比较低的情况后,出现个别复杂度比较高的情况,这种情况就可以使用均摊复杂度。
- 动态数组缩容
public interface List<E> {
/**
* 清除所有元素
*/
void clear();
/**
* 元素数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素
*/
E set(int index,E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index,E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 删除指定元素
* @param element
*/
void remove(E element);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
public class ArrayList<E> implements List<E>{
private int size;//元素的个数
private E[] elements;//所有元素
private static final int DEFAULT_CAPACITY = 10; //默认长度为10;
private static final int ELEMENT_NOT_FOUND = -1;
public ArrayList(int capatity) {
capatity = (capatity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capatity;
//所有的类,最终都继承java.lang.Object
elements = (E[])new Object[capatity];
}
public ArrayList() {
this(DEFAULT_CAPACITY);//无参构造函数调用有参构造函数
}
/**
* 清除所有元素
*/
public void clear() {
//针对数组对象,存储的对象的内存地址,需要把数组中内存地址置为null,意味着对象没有被引用,则对象会被回收
// for(int i = 0;i < size;i++) {
// elements[i] = null;
// }
//根据实际情况指定数组清除的规则,当数组的长度过长,为了节省内存,可清除数组元素
if(size < 100)
//实际上没有把元素清除掉,能提高性能,创建的的数组能重复使用,后续添加元素时,只需覆盖原先元素即可
size = 0;
else
//清空数组的元素
elements = null;
}
/**
* 元素数量
* @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) {
// elements[size++] = element;
// size++;
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);
//取出index位置的元素
E old = elements[index];
//设置index位置的元素
elements[index] = element;
return old;
}
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
public void add(int index,E element) {
// if(element == null) return;
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for(int i = size;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;i++) {
elements[i - 1] = elements[i];
}
// size--;
elements[--size] = null;
return old;
}
/**
* 删除指定元素
* @param element
*/
public void remove(E element) {
remove(indexOf(element));
}
/**
* 查看元素的索引
* @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;
}
/**
* 保证capacity的容量
* @param capacity
*/
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;
System.out.println(oldCapacity + "扩容为:" + newCapacity);
}
private void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ",Size:" + size);
}
private void rangeCheck(int index) {
if(index < 0 || index >= size)
outOfBounds(index);
}
private void rangeCheckForAdd(int index) {
if(index < 0 || index > size)
outOfBounds(index);
}
@Override
public String toString() {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("size = ").append(size).append(", [");
for(int i = 0;i < size;i++) {
//方式一:
// sBuilder = (i != size -1) ? sBuilder.append(elements[i]).append(", ") : sBuilder.append(elements[i]);
//方式二:
// sBuilder.append(elements[i]);
// if(i != size - 1) sBuilder.append(", ");
//方式三:
//方式三优于方式一和方式二,因为不做减法
if(i != 0) sBuilder.append(", ");
sBuilder.append(elements[i]);
}
sBuilder.append("]");
return sBuilder.toString();
}
}
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Person - finalize");
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(obj instanceof Person){
Person person = (Person)obj;
return this.age == person.age;
}
return false;
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Person> person = new ArrayList<>();
person.add(new Person(10,"Jack"));
person.add(new Person(12,"Jack"));
person.add(new Person(13,"Jack"));
person.clear();
// System.out.println(person);
//提醒JVM垃圾回收
System.gc();
ArrayList<Integer> ints = new ArrayList<>();
ints.add(11);
ints.add(22);
ints.add(33);
ints.add(1);
// System.out.println(ints);
}
}
public class Assert {
public static void test(boolean value) {
try {
if(!value) throw new Exception("测试未通过!");
} catch (Exception e) {
e.printStackTrace();
}
}
- List接口
public interface List<E> {
static final int DEFAULT_CAPACITY = 10;//长度默认为10
static final int ELEMENT_NOT_FOUND = -1;
//清除元素
void clear();
//元素个数
int size();
//是否为空
boolean isEmpty();
//是否包含某个元素
boolean contains(E element);
//添加元素
void add(E element);
//获取元素
E get(int index);
//设置元素
E set(int index,E element);
//在index指定位置添加元素
void add(int index,E element);
//删除指定位置元素
E remove(int index);
//删除元素
void remove(E element);
//查看元素的索引
int indexOf(E element);
}
- AbtractList抽象类
public abstract class AbstractList<E> implements List<E> {
//元素个数
protected int size;
//元素个数
@Override
public int size() {
return size;
}
//元素是否为空
@Override
public boolean isEmpty() {
return size == 0;
}
//是否包含元素
@Override
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
//添加元素
@Override
public void add(E element) {
/**
* 最好的情况:O(1);是直接向末尾添加元素
* 最坏的情况:O(n);是数组扩容的时候
* 平均:O((1+1+1+...+1)/n)) = O(1)
* 均摊:O(1)
*/
add(size,element);
}
//边界检查
protected void outOfBounds(int index){
throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size);
}
protected void rangeCheck(int index){
if(index < 0 || index >= size){
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index){
if(index < 0 || index > size){
outOfBounds(index);
}
}
}
- ArrayList类
public class ArrayList<E> extends AbstractList<E> {
private E[] elements;//所有元素
public ArrayList(int capacity){
capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
elements = (E[]) new Object[capacity];
}
public ArrayList(){
this(DEFAULT_CAPACITY);
}
@Override
public void clear() {
for(int i = 0;i < size;i++){
elements[i] = null;
}
size = 0;
//缩容
if(elements != null && elements.length > DEFAULT_CAPACITY){
elements = (E[])new Object[DEFAULT_CAPACITY];
}
}
@Override
public E get(int index) {//O(1)
rangeCheck(index);
return elements[index];
}
@Override
public E set(int index, E element) {//O(1)
rangeCheck(index);
//取出index位置的元素
E old = elements[index];
//设置index位置的元素
elements[index] = element;
return old;
}
@Override
public void add(int index, E element) {
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for(int i = size;i > index;i--){
elements[i + 1] = elements[i];
}
elements[index] = element;
size++;
}
@Override
public E remove(int index) {
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
rangeCheck(index);
E old = elements[index];
for(int i = index + 1;i < size;i++){
elements[i - 1] = elements[i];
}
/**
* 如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作
* 当数组元素被删除,要面临数组的缩容操作
* 比如:剩余空间占总容量的一半是,就进行缩容
*
*/
elements[--size] = null;
//缩容
trim();
return old;
}
@Override
public void remove(E element) {
remove(indexOf(element));
}
@Override
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;
System.out.println(oldCapacity + " 扩容为:" + newCapacity);
}
//缩容
private void trim(){
int oldCapacity = elements.length;
int newCapacity = oldCapacity >> 1;
if(size >= newCapacity || oldCapacity <= DEFAULT_CAPACITY) return;
//剩余空间很多
E[] newElements = (E[]) new Object[newCapacity];
for(int i = 0;i < size;i++){
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + " 缩容为:" + newCapacity);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("size = ").append(size).append(", [");
for(int i = 0;i < size;i++){
if(i != 0) sb.append(",");
sb.append(elements[i]);
}
sb.append("]");
return sb.toString();
}
}
- 测试类
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(11);
list.add(101);
list.add(31);
System.out.println(list);
list.remove(1);
System.out.println(list);
}
}
注意
:扩容倍数、缩容时机设计不当,可能会导致复杂度震荡
2.1.2 链表
- 链表一定要注意0和边界值
- 添加元素----注意0位置
public interface List<E> {
//常量要供外界使用,写在接口中较为合适
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素
*/
E set(int index,E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index,E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 删除指定元素
* @param element
*/
void remove(E element);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
//抽象类是不可见的,只抽取公共代码
public abstract class AbstractList<E> implements List<E>{
//元素个数
protected int size;
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
@Override
public void add(E element) {
add(size,element);
}
//边界检查
protected void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ",Size:" + size);
}
protected void rangeCheck(int index) {
if(index < 0 || index >= size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index) {
if(index < 0 || index > size) {
outOfBounds(index);
}
}
}
public class LinkedList<E> extends AbstractList<E>{
//头节点对象
private Node<E> first;
//定义节点类
private static class Node<E>{
//节点中元素
E element;
//下一个节点
Node<E> next;
public Node(E element,Node<E> next){
this.element = element;
this.next = next;
}
}
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public E get(int index) {
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
return node(index).element;
}
@Override
public E set(int index, E element) {
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
if(index == 0) {
first = new Node<>(element, first);
}else {
Node<E> prev = node(index - 1);
prev.next = new Node<>(element,prev.next);
}
size++;
}
@Override
public E remove(int index) {
/**
* 最好情况:O(1)
* 最坏情况:O(n) ;n代表的是数据规模
* 平均:O((1+2+...+n)/n) = O(n)
*/
rangeCheck(index);
Node<E> node = first;
if(index == 0) {
first = first.next;
}else {
Node<E> prev = node(index - 1);
node = prev.next;
prev.next = node.next;
}
size--;
return node.element;
}
@Override
public void remove(E element) {
// TODO Auto-generated method stub
}
@Override
public int indexOf(E element) {
if(element == null) {
Node<E> node = first;
for(int i = 0;i < size;i++) {
if(node.element == null) return i;
node = node.next;
}
}else {
Node<E> node = first;
for(int i = 0;i < size;i++) {
if(element.equals(node.element)) return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
/**
* 获取index位置对应的节点对象
* @param index
* @return
*/
private Node<E> node(int index){
rangeCheck(index);
Node<E> node = first;
for(int i = 0; i < index;i++) {
node = node.next;
}
return node;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("size=").append(size).append(",[");
Node<E> node = first;
for(int i = 0;i < size;i++) {
if(i != 0) {
sb.append(", ");
}
sb.append(node.element);
node = node.next;
}
// while(node != null) {
//
// node = node.next;
// }
sb.append("]");
return sb.toString();
}
}
-
注意
:所谓增删的时间复杂度:O(1),仅指的是增删那个瞬间。整体上O(n) -
虚拟头节点
public interface List<E> {
//常量要供外界使用,写在接口中较为合适
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素
*/
E set(int index,E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index,E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 删除指定元素
* @param element
*/
void remove(E element);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
//抽象类是不可见的,只抽取公共代码
public abstract class AbstractList<E> implements List<E>{
//元素个数
protected int size;
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
@Override
public void add(E element) {
add(size,element);
}
//边界检查
protected void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ",Size:" + size);
}
protected void rangeCheck(int index) {
if(index < 0 || index >= size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index) {
if(index < 0 || index > size) {
outOfBounds(index);
}
}
}
public class LinkedList<E> extends AbstractList<E>{
//头节点对象
private Node<E> first;
public LinkedList(){
first = new Node<>(null,null);
}
//定义节点类
private static class Node<E>{
//节点中元素
E element;
//下一个节点
Node<E> next;
public Node(E element,Node<E> next){
this.element = element;
this.next = next;
}
}
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
Node<E> prev = index == 0 ? first : node(index - 1);
prev.next = new Node<>(element,prev.next);
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> node = first;
Node<E> prev = index == 0 ? first : node(index - 1);
Node<E> node = prev.next;
prev.next = node.next;
size--;
return node.element;
}
@Override
public void remove(E element) {
// TODO Auto-generated method stub
}
@Override
public int indexOf(E element) {
if(element == null) {
Node<E> node = first;
for(int i = 0;i < size;i++) {
if(node.element == null) return i;
node = node.next;
}
}else {
Node<E> node = first;
for(int i = 0;i < size;i++) {
if(element.equals(node.element)) return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
/**
* 获取index位置对应的节点对象
* @param index
* @return
*/
private Node<E> node(int index){
rangeCheck(index);
Node<E> node = first.next;
for(int i = 0; i < index;i++) {
node = node.next;
}
return node;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("size=").append(size).append(",[");
Node<E> node = first.next;
for(int i = 0;i < size;i++) {
if(i != 0) {
sb.append(", ");
}
sb.append(node.element);
node = node.next;
}
// while(node != null) {
//
// node = node.next;
// }
sb.append("]");
return sb.toString();
}
}
- 动态数组、链表复杂度分析
总结
:链表是节省内存的,而数组不是。
2.1.2.1 删除链表中的节点
- 刪除前
- 刪除后
public class DeleteLinkedListNode {
public class ListNode{
int val;
ListNode next;
ListNode(int val){
this.val = val;
}
}
public void deleteNode(ListNode node){
node.val = node.next.val;
node.next = node.next.next;
}
}
2.1.2.2 反转链表
2.1.2.2.1 递归方法实现
public class ReverseLinkedList {
public class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
}
}
public ListNode reverseLinkedList(ListNode head){
if(head == null || head.next == null) return head;
ListNode newHead = reverseLinkedList(head.next);
head.next.next = head;
return newHead;
}
}
2.1.2.2.2 非递归方法实现
- 反转前
- 反转后
public class ReverseLinkedList {
public class ListNode{
int val;
ListNode next;
public ListNode(int val){
this.val = val;
}
}
public ListNode reverseLinkedList(ListNode head){
if(head == null || head.next == null) return head;
ListNode newHead = null;
while (head != null){
ListNode tmp = head.next;
head.next = newHead;
newHead = head;
head = tmp;
}
return newHead;
}
}
2.1.3 双向链表
- gc root对象
- 1) 被栈指针(局部变量 )指向的对象
- 1) 被栈指针(局部变量 )指向的对象
- List接口
public interface List<E> {
int ELEMENT_NOT_FOUND = -1;
//元素个数
int size();
//清空元素
void clear();
//是否为空
boolean isEmpty();
//是否包含元素
boolean contains(E element);
//添加元素
void add(E element);
//指定位置添加元素
void add(int index,E element);
//获取元素
E get(int index);
//设置元素
E set(int index,E element);
//删除指定位置的元素
E remove(int index);
//删除元素
void remove(E element);
//查看元素的索引
int indexOf(E element);
}
- AbstractList抽象类
public abstract class AbstractList<E> implements List<E> {
//元素个数
protected int size;
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
@Override
public void add(E element) {
add(size,element);
}
protected void outOfBounds(int index){
throw new IndexOutOfBoundsException("Index : " + index + ",Size : " + size);
}
protected void rangeCheck(int index){
if(index < 0 || index >= size) outOfBounds(index);
}
protected void rangeCheckForAdd(int index){
if(index < 0 || index > size) outOfBounds(index);
}
}
- LinkedList类
public class LinkedList<E> extends AbstractList<E>{
private Node<E> first;
private Node<E> last;
private static class Node<E>{
E element;
Node<E> prev;
Node<E> next;
public Node(Node<E> prev,E element,Node<E> next){
this.prev = prev;
this.element = element;
this.next = next;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if(prev != null){
sb.append(prev.element);
}else{
sb.append("null");
}
sb.append("_").append(element).append("_");
if(next != null){
sb.append(next.element);
}else{
sb.append("null");
}
return sb.toString();
}
}
@Override
public void clear() {
size = 0;
first = null;
last = null;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if(index == size){
Node<E> oldLast = last;
last = new Node<>(oldLast,element,null);
if(oldLast == null){//没有元素
first = last;
}else{
oldLast.next = last;
}
}else{
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<>(prev,element,next);
next.prev = node;
if(prev == null){
first = node;
}else{
prev.next = node;
}
}
size++;
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
E old = node(index).element;
node(index).element = element;
return old;
}
@Override
public E remove(int index) {
Node<E> node = node(index);
Node<E> prev = node.prev;
Node<E> next = node.next;
if(prev == null){//index == 0
first = next;
}else{
prev.next = next;
}
if(next == null){//index == size - 1
last = prev;
}else{
next.prev = prev;
}
size--;
return node.element;
}
@Override
public void remove(E element) {
}
@Override
public int indexOf(E element) {
if(element == null){
Node<E> node = first;
for(int i = 0;i < size;i++){
if(node.element == null) return i;
node = node.next;
}
}else{
Node<E> node = first;
for(int i = 0;i < size;i++){
if(element.equals(node.element)) return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
private Node<E> node(int index){
rangeCheck(index);
if(index < (size >> 1)){
Node<E> node = first;
for(int i = 0;i < index;i++){
node = node.next;
}
return node;
}else{
Node<E> node = last;
for(int i = size - 1;i > index;i--){
node = node.prev;
}
return node;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("size = ").append(size).append(",[");
Node<E> node = first;
for(int i = 0;i < size;i++){
if(i != 0) sb.append(", ");
// sb.append(node.element);
sb.append(node);
node = node.next;
}
sb.append("]");
return sb.toString();
}
}
- 双向链表VS单向链表
- 双向链表VS动态数组
2.1.4 单向循环链表
- List接口
package com.test.circle;
public interface List<E> {
static final int ELEMENT_NOT_FOUND = -1;
//清空元素
void clear();
//元素数量
int size();
//是否为空
boolean isEmpty();
//是否包含元素
boolean contains(E element);
//添加元素
void add(E element);
//指定位置添加元素
void add(int index,E element);
//获取元素
E get(int index);
//设置元素
E set(int index,E element);
//删除指定位置的元素
E remove(int index);
//删除元素
void remove(E element);
//查看元素的索引
int indexOf(E element);
}
- Abstract抽象类
public abstract class AbstractList<E> implements List<E> {
//元素的个数
protected int size;
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
@Override
public void add(E element) {
add(size,element);
}
public void outOfBounds(int index){
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
public void rangeCheck(int index){
if(index < 0 || index >= size){
outOfBounds(index);
}
}
public void rangeCheckForAdd(int index){
if(index < 0 || index > size){
outOfBounds(index);
}
}
}
- SingleCircleLinkedList
public class SingleCircleLinkedList<E> extends AbstractList<E>{
//头节点对象
private Node<E> first;
//定义节点类
private class Node<E>{
E element;
Node<E> next;
public Node(E element, Node<E> next){
this.element = element;
this.next = next;
}
// @Override
// public String toString() {
// StringBuilder sb = new StringBuilder();
//
// sb.append(element).append("_").append(next.element);
// return sb.toString();
// }
}
//虚拟头节点:为了让代码更加精简,统一所有节点的处理逻辑,可以在最前面增加一个虚拟的头节点(不存储数据)
//获取index位置对应的节点对象
private Node<E> node(int index){
rangeCheck(index);
Node<E> node = first;
for(int i = 0;i < index;i++){
node = node.next;
}
return node;
}
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public void add(int index, E element) {
if(index == 0){
Node<E> newFirst= new Node<>(element,first);
//拿到最后一个节点
Node<E> last = (size == 0) ? newFirst : node(size - 1);
last.next = newFirst;
first = newFirst;
}else{
Node<E> prev = node(index - 1);
prev.next = new Node<>(element,prev.next);
}
size++;
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
}
@Override
public E remove(int index) {
Node<E> node = first;
if(index == 0){
if(index == 0){
first = null;
}else{
Node<E> last = node(size - 1);
first = first.next;
last.next = first;
}
}else{
Node<E> prev = node(index - 1);
node = prev.next;
prev.next = node.next;
}
size--;
return node.element;
}
@Override
public void remove(E element) {
remove(indexOf(element));
}
@Override
public int indexOf(E element) {
if(element == null){
Node<E> node = first;
for(int i = 0;i < size;i++){
if(node.element == null) return i;
node = node.next;
}
}else{
Node<E> node = first;
for(int i = 0;i < size;i++){
if(element.equals(node.element)) return i;
}
node = node.next;
}
return ELEMENT_NOT_FOUND;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("size = ").append(size).append(",[");
Node<E> node = first;
for(int i = 0;i < size;i++){
if(i != 0) sb.append(",");
sb.append(node.element);
node = node.next;
}
sb.append("]");
return sb.toString();
}
}
、斐波那契数列
public class Main {
/**
* 斐波那契数列:
* 0 1 1 2 3 5 8 13 ...
* index: 0 1 2 3 4 5 6 7 ...
*/
//递归
public static int fib1(int n) {
if(n <= 1) return n;
return fib1(n - 1) + fib1(n-2);
}
public static int fib2(int n) {
if(n <= 1) return n;
int first = 0;
int second = 1;
//前一个数加后一个数的次数与index的关系是n-1
for(int i = 0;i < n -1;i++) {
int sum = first + second;
//把second的值给下一次的第一个数
first = second;
//把sum的值给下一次的第二个数
second = sum;
}
//最后结果肯定在second手里
return second;
}
//fib3比fib2定义的变量要少,因此在空间复杂度上要低
public static int fib3(int n) {
if(n <= 1) return n;
int first = 0;
int second = 1;
while(n-- > 1){
second += first;
first = second - first;
}
return second;
}
public static void main(String[] args) {
// System.out.println(fib1(64));
// System.out.println(fib2(64));
System.out.println(fib3(64));
}
}
、排序
- 常见排序列表
2.1 选择排序
- 最简单但是最没用(O(n^2);不稳定)的排序算法,也有优化空间
/**
* 选择排序
*/
public class SelectionSort {
public static void main(String[] args) {
//定义数组
int[] arr = {5,3,6,8,1,7,9,4,2};
//因假设把第0个值定义为最小值的位置,所以循环次数为arr.length - 1
for(int i = 0; i < arr.length - 1;i++){
//假设最小值的最开始位置,这个值随着外循环的i而变化
int minPos = i;
//找出数组中最小值的位置,内循环开始比较的位置是i+1
for(int j = i + 1;j < arr.length; j++){
// if(arr[j] < arr[minPos]) minPos = j;
//三元表达式
minPos = arr[j] < arr[minPos] ? j : minPos;
}
//打印最小值的位置
System.out.println("\nminPos:" + minPos);
swap(arr, i, minPos);
System.out.println("经过第" + i + "次循环之后,数组的内容:");
print(arr);
}
System.out.println("\n经过选择排序后,数组的内容为:");
print(arr);
}
//值交换的方法
static void swap(int[] arr, int i, int j){
//追尾法---值交换
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//存在重复的代码,需抽离出来,
static void print(int[] arr){
for(int i = 0;i < arr.length;i++){
//打印数组
System.out.print(arr[i] + " ");
}
}
}
- 大O分析
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 不稳定