动态数组
动态数组是顺序存储结构,查找,赋值速度很快。
动态数组最灵活、最方便,有助于有效管理内存。例如,可短时间使用一个大数组,然后,在不使用这个数组时,将内存空间释放给系统。
如果不用动态数组,就要声明一个数组,它的大小尽可能达到最大,然后再抹去那些不必要的元素。但是,如果过度使用这种方法,会导致内存的操作环境变慢。
package com.ldg;
@SuppressWarnings("unchecked")
public class ArryList<T> extends AbstractList<T> {
// 数组
private T[] elements;
private static final int DEFAULT_CAPACITY = 2;
/**
* 在最后添加元素
*
* @param element
*/
public void add(T element) {
add(size, element);
}
/**
* 根据索引移除元素
*
* @param index
* @return 被移除前数据
*/
public T remove(int index) {
isOutSize(index);
T old = elements[index];
for (int i = index; i < size - 1; i++) {
elements[i] = elements[i + 1];
}
size--;
elements[size] = null;
return old;
}
/**
* 根据索引更改元素
*
* @param index
* @param element
* @return 被改前数据
*/
public T set(int index, T element) {
isOutSize(index);
T old = elements[index];
elements[index] = element;
return old;
}
/**
* 清除数组
*/
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
public T get(int index) {
isOutSize(index);
return elements[index];
}
/**
*
* @param index
* @param element
* @return 原始数据
*/
public T add(int index, T element) {
// 允许size==index
isOutSizeForAdd(index);
enSureAddCapacity(index);
T old = elements[index];
elements[index] = element;
for (int i =size - 1; i > index; i--) {
elements[i + 1] = elements[i];
}
size++;
return old;
}
/**
*
* @param element
* @return 返回出现该数据的第一个索引
*/
public int indexOf(T element) {
for (int i = 0; i < size; i++) {
if (elements[i].equals(element)) {
return i;
}
}
return ELEMENT_NOT_FOUND;
}
public ArryList() {
// 默认只能存放2个对象
// 引用泛型会有内存管理问题。
elements = (T[]) new Object[DEFAULT_CAPACITY];
}
public ArryList(int capacity) {
if (capacity <= 0)
capacity = 2;
elements = (T[]) new Object[capacity];
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size:" + size + " ArryList:").append("[");
for (int i = 0; i < size; i++) {
if (i > 0) {
stringBuilder.append(",");
}
stringBuilder.append(elements[i]);
}
stringBuilder.append("]");
return stringBuilder.toString();
}
public void enSureAddCapacity(int index) {
int oldCapacity = elements.length;
// 位运算符 扩容一倍 左移一位为*2 右移一位为/2
int newCapacity = oldCapacity << 1;
if (index == oldCapacity) {
T[] newElements = (T[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + " 扩容为 " + newCapacity);
}
}
}
单链表
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
package com.ldg.single;
import java.util.IllegalFormatCodePointException;
import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID;
import com.ldg.AbstractList;
@SuppressWarnings("unused")
//单链表类
public class LinkedList<T> extends AbstractList<T> {
// 指的是首节点 由首节点指向链表
private Node<T> first;
// 声明节点类
@SuppressWarnings("hiding")
private class Node<T> {
T element;
Node<T> next;
public Node(T element, Node<T> next) {
this.element = element;
this.next = next;
}
}
/**
* 根据序号返回节点 从首节点一个个next
*
* @param index
* @return
*/
public Node<T> node(int index) {
//判断序号是否越界
isOutSize(index);
Node<T> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
/**
* 根据索引添加元素 返回原始值 注意index=0 index=size index=size-1的边界情况
*/
@Override
public T add(int index, T element) {
T old;
if (index == 0) {
if (first == null) {
old = null;
} else {
old = first.element;
}
first = new Node<T>(element, first);
} else {
Node<T> node = node(index - 1).next;
if (node == null) {
old = null;
} else {
old = node.element;
}
node(index - 1).next = new Node<T>(element, node(index - 1).next);
}
size++;
return old;
}
@Override
public void add(T element) {
add(size, element);
}
@Override
public T remove(int index) {
isOutSize(index);
T old;
if (index == 0) {
old = first.element;
first = first.next;
} else {
old = node(index).element;
node(index - 1).next = node(index - 1).next.next;
}
size--;
return old;
}
@Override
public T set(int index, T element) {
T old = node(index).element;
node(index).element = element;
return old;
}
@Override
public void clear() {
size = 0;
first = null;
}
@Override
public T get(int index) {
return node(index).element;
}
@Override
public int indexOf(T element) {
Node<T> node = first;
for (int i = 0; i < size; i++) {
if (node.element.equals(element)) {
return i;
}
node = node.next;
}
return ELEMENT_NOT_FOUND;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + size + " LinkedList[");
for (int i = 0; i < size; i++) {
if (i != 0) {
stringBuilder.append(",");
}
stringBuilder.append(node(i).element);
}
stringBuilder.append("]");
return stringBuilder.toString();
}
/***
* 反转链表
*
* @param head
* @return
*/
public Node<T> reverseList(Node<T> head) {
if (head == null || head.next == null)
return head;
// 与当前链表关联 这样才不会出现空指针
first = reverseList(head.next);
head.next.next = head;
head.next = null;
return first;
}
}
双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
ps:注意一下节点中两指针的指向。不要漏掉。
package com.ldg.doubles;
import java.util.IllegalFormatCodePointException;
import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID;
import com.ldg.AbstractList;
@SuppressWarnings("unused")
//双向链表类
public class LinkedList<T> extends AbstractList<T> {
// 指的是首节点 由首节点指向链表
private Node<T> first;
// 尾节点
private Node<T> last;
// 声明节点类
@SuppressWarnings("hiding")
private class Node<T> {
T element;
// 后一个节点
Node<T> next;
// 前一个节点
Node<T> pre;
public Node(Node<T> pre, T element, Node<T> next) {
this.pre = pre;
this.element = element;
this.next = next;
}
}
/**
* 根据序号返回节点 分情况从头或者尾开始移动
*
* @param index
* @return
*/
public Node<T> node(int index) {
// 判断序号是否越界
isOutSize(index);
Node<T> node = null;
if (index < size >> 2) {
node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
} else {
node = last;
for (int i = size - 1; i > index; i--) {
node = node.pre;
}
}
return node;
}
/**
* 注意一下节点中两个指针的指向.不要漏忘
* 根据索引添加元素 返回原始值 注意index=0 index=size index=size-1的边界情况
*/
@Override
public T add(int index, T element) {
T old;
// 直接添加到链表最后面
if (index == size) {
old = null;
Node<T> pre = last;
Node<T> node = new Node<T>(pre, element, null);
last = node;
if (pre == null) // 当index=size=0;
{
first = node;
} else {
pre.next = node;
}
} else {
Node<T> next = node(index);
old = next.element;
Node<T> pre = node(index).pre;
Node<T> node = new Node<T>(pre, element, next);
if (pre == null)// index=0
{
first = node;
} else {
pre.next = node;
}
next.pre=node;
}
size++;
return old;
}
/**
* 添加
*/
@Override
public void add(T element) {
add(size, element);
}
/**
* 移除节点
*/
@Override
public T remove(int index) {
isOutSize(index);
T old = null;
Node<T> next = node(index).next;
Node<T> pre = node(index).pre;
if (pre == null) //index=0的情况
{
first = next;
} else {
pre.next = next;
}
if(next==null) //index=size-1的情况;
{
last=pre;
}
else {
next.pre = pre;
}
size--;
return old;
}
@Override
public T set(int index, T element) {
T old = node(index).element;
node(index).element = element;
return old;
}
// 如果不是被gc root对象指向的内存地址块会被java回收站机制回收。
// 就是没局部变量指向的对象。
@Override
public void clear() {
size = 0;
first = null;
last = null;
}
@Override
public T get(int index) {
return node(index).element;
}
@Override
public int indexOf(T element) {
Node<T> node = first;
for (int i = 0; i < size; i++) {
if (node.element.equals(element)) {
return i;
}
node = node.next;
}
System.out.println(size);
return ELEMENT_NOT_FOUND;
}
// Stringbuilder的拼接
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Size:" + size + " LinkedList[");
for (int i = 0; i < size; i++) {
if (i != 0) {
stringBuilder.append(",");
}
System.out.println(i);
stringBuilder.append(node(i).element);
}
stringBuilder.append("]");
System.out.println(size);
return stringBuilder.toString();
}
/***
* 反转链表
*
* @param head
* @return
*/
public Node<T> reverseList(Node<T> head) {
if (head == null || head.next == null)
return head;
// 与当前链表关联 这样才不会出现空指针
first = reverseList(head.next);
head.next.next = head;
head.pre = head.next;
last = head;
return first;
}
}
以上代码经测试都能跑通。