自己实现简单动态数组,单链表,双向链表

动态数组
动态数组是顺序存储结构,查找,赋值速度很快。
动态数组最灵活、最方便,有助于有效管理内存。例如,可短时间使用一个大数组,然后,在不使用这个数组时,将内存空间释放给系统。
如果不用动态数组,就要声明一个数组,它的大小尽可能达到最大,然后再抹去那些不必要的元素。但是,如果过度使用这种方法,会导致内存的操作环境变慢。

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;

	}

}

以上代码经测试都能跑通。

发布了23 篇原创文章 · 获赞 17 · 访问量 1290

猜你喜欢

转载自blog.csdn.net/qq_41587409/article/details/105031964
今日推荐