链表
我们知道数组是一种通用的数据结构,能用来实现栈、队列等很多数据结构。而链表也是一种使用广泛的通用数据结构,它也可以用来作为实现栈、队列等数据结构的基础,基本上除非需要频繁的通过下标来随机访问各个数据,否则很多使用数组的地方都可以用链表来代替。
但是我们需要说明的是,链表是不能解决数据存储的所有问题的,它也有它的优点和缺点。本篇博客我们介绍几种常见的链表,分别是单向链表、双向链表。
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
单向链表(Single-Linked List)
单链表是链表中结构最简单的。一个单链表的节点(Node)分为两个部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分存储下一个节点的地址。最后一个节点存储地址的部分指向空值。
单向链表只可向一个方向遍历,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前插入的节点设置为头节点,next指向原头节点即可。删除一个节点,我们将该节点的上一个节点的next指向该节点的下一个节点。
package com.ys.datastructure;
public class SingleLinkedList {
private int size;
private Node head;
//构造函数
public SingleLinkedList(){
size = 0;
head = null;
}
//节点类
private class Node{
private Object data;
private Node next;
public Node(Object data){
this.data = data;
}
}
//插入结点
public Object addHead(Object data){
Node newHead = new Node(data);
if(size == 0){
head = newHead;
}else{
newHead.next = head;
head = newHead;
}
size++;
return data;
}
//删除头结点
public Object deleteHead(){
Object data = null;;
if(size == 0){
System.out.println("空链表,无法删除元素!");
}else if(size == 1){
data = head.data;
head = null;
}else if(size > 1){
data = head.data;
head = head.next;
}
size--;
return data;
}
//查找节点
public Node find(Object data){
Node temp = head;
for(int i=0;i < size;i++){
if(data.equals(temp.data)){
return temp;
}else{
temp = temp.next;
}
}
return null;
}
//删除指点节点
public boolean delete(Object data){
if(size == 0){
System.out.println("空链表,无法删除元素!");
return false;
}
if(data.equals(head.data)){
deleteHead();
size--;
return true;
}
Node temp = head;
for(int i=0;i < size;i++){
if(data.equals(temp.next.data)){
temp.next = temp.next.next;
size--;
return true;
}else{
temp = temp.next;
}
}
return false;
}
//判断链表是否为空
public boolean isEmpty(){
if(size == 0){
return true;
}else{
return false;
}
}
//打印全部链表
public void display(){
Node temp = head;
if(size == 0){
System.out.println("[]");
}else if(size == 1){
System.out.println(head.data);
}else{
for(int i=0;i<size;i++){
System.out.print(temp.data+"->");
temp = temp.next;
}
}
}
}
双向链表
我们知道单向链表只能从一个方向遍历,那么双向链表它可以从两个方向遍历。
package com.ys.datastructure;
public class TwoWayLinkedList {
private Node head;//表示链表头
private Node tail;//表示链表尾
private int size;//表示链表的节点个数
private class Node{
private Object data;
private Node next;
private Node prev;
public Node(Object data){
this.data = data;
}
}
public TwoWayLinkedList(){
size = 0;
head = null;
tail = null;
}
//在链表头增加节点
public void addHead(Object value){
Node newNode = new Node(value);
if(size == 0){
head = newNode;
tail = newNode;
size++;
}else{
head.prev = newNode;
newNode.next = head;
head = newNode;
size++;
}
}
//在链表尾增加节点
public void addTail(Object value){
Node newNode = new Node(value);
if(size == 0){
head = newNode;
tail = newNode;
size++;
}else{
newNode.prev = tail;
tail.next = newNode;
tail = newNode;
size++;
}
}
//删除链表头
public Node deleteHead(){
Node temp = head;
if(size != 0){
head = head.next;
head.prev = null;
size--;
}
return temp;
}
//删除链表尾
public Node deleteTail(){
Node temp = tail;
if(size != 0){
tail = tail.prev;
tail.next = null;
size--;
}
return temp;
}
//获得链表的节点个数
public int getSize(){
return size;
}
//判断链表是否为空
public boolean isEmpty(){
return (size == 0);
}
//显示节点信息
public void display(){
if(size >0){
Node node = head;
int tempSize = size;
if(tempSize == 1){//当前链表只有一个节点
System.out.println("["+node.data+"]");
return;
}
while(tempSize>0){
if(node.equals(head)){
System.out.print("["+node.data+"->");
}else if(node.next == null){
System.out.print(node.data+"]");
}else{
System.out.print(node.data+"->");
}
node = node.next;
tempSize--;
}
System.out.println();
}else{//如果链表一个节点都没有,直接打印[]
System.out.println("[]");
}
}
}