java数据结构之链表

链表

 1. 定义:链表通常由一连串节点组成,每个节点包含任意的实例数据和一个或两个用来指向上一个/下一个节点的位置的链接
 2. 存储结构:链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是不会按线性的顺序存储数据,而是在每一个节点上存放下一个节点的指针(Pointer)
 3. 特征:使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,灵活的内存动态管理。但是链表失去了数组随机读取的有点,同时链表由于增加了结点的指针域,空间开销较大。

单链表

说明:

 单链表的节点(Node)分为两部分,第一部分数据域(data)保存节点数据信息,另一部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。
 ![在这里插入图片描述](https://www.icode9.com/i/ll/?i=20190224202755834.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3podXNoYW9fMTIyOQ==,size_16,color_FFFFFF,t_70)

代码实现

 package com.hulm.link;

/**
 * 单链表
 */
public class SingleLinked<T> {
	// 链表对象类
	@SuppressWarnings("hiding")
	private class Node<T> {
		// 当前节点数据
		private T data;
		// 下一个节点
		private Node<T> next;

		// 初始化一个节点
		public Node(T data, Node<T> next) {
			this.data = data;
			this.next = next;
		}

		// 获取节点数据
		public T getData() {
			return data;
		}
	}

	// 头节点
	private Node<T> head;
	// 链表的长度
	private int size;

	// 构造器初始化链表
	public SingleLinked() {
		this.head = null;
		this.size = 0;
	}

	// 判断链表是否为空
	public boolean isEmpty() {
		return size == 0;
	}

	// 获取链表的长度
	public int size() {
		return size;
	}

	// 在链表的末尾插入一个元素
	public void add(T e) {
		// 如果链表为空,把数据插入到头节点
		if (isEmpty()) {
			head = new Node<T>(e, null);
			head.next = null;
		} else {
			// 获取头节点
			Node<T> temp = head;
			// 遍历向后查找,查找到最后一个节点
			while (temp.next != null) {
				temp = temp.next;
			}
			temp.next = new Node<T>(e, null);
		}
		size++;
	}

	// 在指定位置添加
	public void insert(int index, T e) {
		if (index < 0 || index > size()) {
			throw new ArrayIndexOutOfBoundsException("插入位置不合法");
		}
		// 如果节点为头节点
		if (index == 0) {
			Node<T> temp = head;
			head = new Node<T>(e, temp);
		} else if (index < size()) {
			// 获取指定位置的上一个节点
			Node<T> temp = head;
			for (int i = 0; i < index - 1; i++) {
				temp = temp.next;
			}
			Node<T> preNode = temp;
			// 获取当前节点
			Node<T> currNode = getNode(index);
			// 创建要插入的节点
			Node<T> insertNode = new Node<T>(e, currNode);
			// 将上一个节点的next节点指向当前节点的下一个节点
			preNode.next = insertNode;
			// 在尾部插入节点
		} else {
			// 获取头节点
			Node<T> temp = head;
			// 遍历向后查找,查找到最后一个节点
			while (temp.next != null) {
				temp = temp.next;
			}
			temp.next = new Node<T>(e, null);
		}
		size++;
	}

	// 获取指定位置元素节点
	private Node<T> getNode(int index) {
		// 检查位置是否合法
		checkPosition(index);
		Node<T> temp = head;
		for (int i = 0; i < index; i++) {
			temp = temp.next;
		}
		return temp;
	}

	// 获取指定位置的节点数据
	public T get(int index) {
		return getNode(index).getData();
	}

	// 删除指定位置元素
	public void remove(int index) {
		// 验证位置是否合法
		checkPosition(index);
		// 如果节点为头节点
		if (index == 0) {
			head = head.next;
		} else {
			// 获取指定位置的上一个节点
			Node<T> temp = head;
			for (int i = 0; i < index - 1; i++) {
				temp = temp.next;
			}
			Node<T> preNode = temp;
			// 获取下一个节点
			Node<T> nextNode = getNode(index).next;
			// 将上一个节点的next节点指向当前节点的下一个节点
			preNode.next = nextNode;
		}
		size--;
	}

	// 判断位置是否合法
	public void checkPosition(int index) {
		// 如果输入的位置小于0获取大于size-1,则返回越界异常
		if (index < 0 || index > size() - 1) {
			throw new ArrayIndexOutOfBoundsException("位置不合法");
		}
	}

	// 重写toString方法
	public String toString() {
		if (size() == 0) {
			return "[]";
		} else {
			StringBuilder sb = new StringBuilder("[");
			// 获取头节点
			Node<T> temp = head;
			// 遍历向后查找,查找到最后一个节点
			while (temp.next != null) {
				sb.append(temp.getData() + ", ");
				temp = temp.next;
			}
			sb.append(temp.getData());
			sb.append("]");
			return sb.toString();
		}
	}
}

单链表的测试类

package com.hulm.link;

public class TestSingleLinked {
  public static void main(String[] args) {
  	SingleLinked<Integer> sl = new SingleLinked<Integer>();
  	sl.add(1);
  	sl.add(2);
  	sl.add(4);
  	sl.add(5);
  	System.out.println(sl);
  	System.out.println(sl.get(3));
  	System.out.println(sl);
  	sl.remove(2);
  	System.out.println(sl);

  	sl.insert(1, 11);
  	System.out.println(sl);
  	sl.insert(0, 0);
  	System.out.println(sl);
  	System.out.println(sl.get(4));
  	sl.insert(5, 22);
  	System.out.println(sl);
  }
}

双链表

  双链表的节点(Node)分为三部分,第一部分存储上一个节点的地址,第二部分数据域(data)保存节点数据信息,第三部分存储下一个节点的地址。第一个节点的上一个节点地址指向空值,最后一个节点存储地址的部分指向空值。
  ![在这里插入图片描述](https://www.icode9.com/i/ll/?i=20190224204429364.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3podXNoYW9fMTIyOQ==,size_16,color_FFFFFF,t_70)

双链表的实现

package com.hulm.link;

/**
* 双链表
*/
public class DoubleLinked<T> {
  // 链表对象类
  @SuppressWarnings("hiding")
  private class Node<T> {
  	// 前一个节点
  	private Node<T> prev;
  	// 当前节点数据
  	private T data;
  	// 下一个节点
  	private Node<T> next;

  	// 初始化一个节点
  	public Node(Node<T> prev, T data, Node<T> next) {
  		this.prev = prev;
  		this.data = data;
  		this.next = next;
  	}

  	// 获取节点数据
  	public T getData() {
  		return data;
  	}
  }

  // 头节点
  private Node<T> head;
  // 尾部节点
  private Node<T> tail;
  // 链表的长度
  private int size;

  // 构造器初始化链表
  public DoubleLinked() {
  	this.head = tail = null;
  	this.size = 0;
  }

  // 判断链表是否为空
  public boolean isEmpty() {
  	return size == 0;
  }

  // 获取链表的长度
  public int size() {
  	return size;
  }

  // 在链表的末尾插入一个元素
  public void add(T e) {
  	// 如果链表为空,把数据插入到头节点
  	if (isEmpty()) {
  		head = new Node<T>(null, e, tail);
  		head.next = null;
  	} else {
  		// 获取头节点
  		Node<T> temp = head;
  		// 遍历向后查找,查找到最后一个节点
  		while (temp.next != null) {
  			temp = temp.next;
  		}
  		temp.next = new Node<T>(temp, e, null);
  		tail = temp.next;
  	}
  	size++;
  }

  // 在指定位置添加
  public void insert(int index, T e) {
  	if (index < 0 || index > size()) {
  		throw new ArrayIndexOutOfBoundsException("插入位置不合法");
  	}
  	// 如果节点为头节点
  	if (index == 0) {
  		Node<T> temp = head;
  		head = new Node<T>(null, e, temp);
  		temp.prev = head;
  	} else if (index < size()) {
  		// 获取指定位置的上一个节点
  		Node<T> temp = head;
  		for (int i = 0; i < index - 1; i++) {
  			temp = temp.next;
  		}
  		Node<T> preNode = temp;
  		// 获取当前节点
  		Node<T> currNode = getNode(index);
  		// 创建要插入的节点
  		Node<T> insertNode = new Node<T>(preNode, e, currNode);
  		// 将上一个节点的next节点指向当前节点的下一个节点
  		preNode.next = insertNode;
  		currNode.prev = insertNode;
  		// 在尾部插入节点
  	} else {
  		// 获取头节点
  		Node<T> temp = tail;
  		// 要插入的节点
  		Node<T> insertNode = new Node<T>(temp, e, null);
  		temp.next = insertNode;
  	}
  	size++;
  }

  // 获取指定位置元素节点
  private Node<T> getNode(int index) {
  	// 检查位置是否合法
  	checkPosition(index);
  	// 定义链表的中间位置
  	int mid = size >> 1;
  	// 定义临时节点
  	Node<T> temp = null;
  	// 如果位置在mid之前
  	if (index <= mid) {
  		temp = head;
  		for (int i = 0; i < mid; i++) {
  			temp = temp.next;
  		}
  		// 如果位置在mid之后
  	} else if (index > mid) {
  		temp = tail;
  		for (int i = size() - 1; i > mid; i--) {
  			temp = temp.prev;
  		}
  	}
  	return temp;
  }

  // 获取指定位置的节点数据
  public T get(int index) {
  	return getNode(index).getData();
  }

  // 删除指定位置元素
  public void remove(int index) {
  	// 验证位置是否合法
  	checkPosition(index);
  	// 如果节点为头节点
  	if (index == 0) {
  		head = head.next;
  	} else {
  		// 获取指定位置的上一个节点
  		Node<T> temp = head;
  		for (int i = 0; i < index - 1; i++) {
  			temp = temp.next;
  		}
  		Node<T> preNode = temp;
  		// 获取下一个节点
  		Node<T> nextNode = getNode(index).next;
  		// 将上一个节点的next节点指向当前节点的下一个节点
  		preNode.next = nextNode;
  	}
  	size--;
  }

  // 判断位置是否合法
  public void checkPosition(int index) {
  	// 如果输入的位置小于0获取大于size-1,则返回越界异常
  	if (index < 0 || index > size() - 1) {
  		throw new ArrayIndexOutOfBoundsException("位置不合法");
  	}
  }

  // 重写toString方法
  public String toString() {
  	if (size() == 0) {
  		return "[]";
  	} else {
  		StringBuilder sb = new StringBuilder("[");
  		// 获取头节点
  		Node<T> temp = head;
  		// 遍历向后查找,查找到最后一个节点
  		while (temp.next != null) {
  			sb.append(temp.getData() + ", ");
  			temp = temp.next;
  		}
  		sb.append(temp.getData());
  		sb.append("]");
  		return sb.toString();
  	}
  }

}

##双链表的测试类

package com.hulm.link;

public class TestDoubleLinked {
   public static void main(String[] args) {
   	DoubleLinked<Integer> sl = new DoubleLinked<Integer>();
   	sl.add(1);
   	sl.add(2);
   	sl.add(4);
   	sl.add(5);
   	System.out.println(sl);
   	System.out.println(sl.get(3));
   	System.out.println(sl);
   	sl.remove(2);
   	System.out.println(sl);

   	sl.insert(1, 11);
   	System.out.println(sl);
   	sl.insert(0, 0);
   	System.out.println(sl);
   	System.out.println(sl.get(4));
   	sl.insert(5, 22);
   	System.out.println(sl);
   }
}

作者:宿命__胡
来源:CSDN
原文:https://blog.csdn.net/zhushao_1229/article/details/87905538
版权声明:本文为博主原创文章,转载请附上博文链接!

上一篇:P1141 01迷宫


下一篇:打印出数字字符串的偶位数