之前学习数据结构,都是用C语言来实现的,最近打算用Java实现一下,加深理解。
先看节点的定义:
// 节点结构
class Node {
int data; // 数据域
Node next; // 指针域
public Node(int data){
this(data,null);
}
public Node(int data,Node next){
this.data = data;
this.next = next;
}
}
一个节点,包括了数据域和指针域,其中,指针域保存是下一个节点的地址,也就是指向下一个节点。
本文实现的单链表,是带有头结点的,因为头结点的存在,可以使很多操作变得方便。
1. 遍历链表
想要直观的知道链表数据是怎样的,那就得遍历它:
/**
* 打印链表
*/
public void print(){
Node tmp = head.next; // 指向第一个节点
while (tmp != null){
System.out.print(tmp.data+" -> ");
tmp = tmp.next;
}
System.out.println();
}
这里的head,便是头结点,一般不存储值,其指针指向真正意义上的第一个节点。
2. 插入
(1)头插法
/**
* 头插法插入
* @param value
*/
public void insertHead(int value){
// 要插入的新节点
Node newNode = new Node(value);
newNode.next = head.next;
head.next = newNode;
}
这个应该比较好理解,头插法,就是新插入的节点放在头部,实现上主要是两步:
a. 新节点指向第一个节点
b. 新节点成为第一个节点
(2)尾插法
/**
* 尾插法插入
* @param value
*/
public void insertTail(int value){
// 找到最后一个节点,其指针域next为null
Node tmp = head;
while (tmp.next != null){
tmp = tmp.next;
}
// 跳出循环,则tmp为最后一个节点
Node newNode = new Node(value);
// 让新节点,成为新的尾节点
tmp.next = newNode;
}
尾插法的关键是,找到最后一个节点,然后让新节点成为最后一个节点。
(3)指定位置插入
/**
* 在指定位置插入
* @param position
* @param value
* @return
*/
public boolean insert(int position,int value){
// +1,是因为可以插入到最后,相当于尾插法的效果
if (position < 1 || position > this.getLength()+1){
System.out.println(position+",待插入的位置不正确,位置范围应是1到"+(this.getLength()+1));
return false;
}
// 找到要插入位置的前一个节点
Node node = this.findByPosition(position - 1);
Node newNode = new Node(value);
newNode.next = node.next;
node.next = newNode;
return true;
}
要想在指定位置插入,关键是找到它的前一个节点。
3. 查找
(1)根据位置查找
/**
* 查找第position个节点,position从0开始,0表示的是头结点,没有实际意义
* @param position
* @return
*/
public Node findByPosition(int position){
if (position < 0 || position > this.getLength()){
System.out.println(position+",不在查找的范围内,查找的范围应是0到"+this.getLength());
return null;
}
Node tmp = head;
// 从头节点开始查找
int i = 1;
while (tmp.next != null && i <= position){
tmp = tmp.next;
i++;
}
return tmp;
}
(2)根据值查找
/**
* 查找value所在的(第一个的)节点
* @param value
* @return
*/
public Node findByValue(int value){
Node tmp = head.next;
while (tmp != null){
if (tmp.data == value){
return tmp;
}
tmp = tmp.next;
}
return null;
}
4. 删除
(1)根据位置删除
/**
* 移除第position个节点
* @param position
* @return
*/
public boolean remove(int position){
// 判断位置的合理性
if (position < 1 || position > this.getLength()){
System.out.println(position+",删除的位置不正确,位置范围应是1到"+this.getLength());
return false;
}
// 查找待删除节点是前一个
Node node = findByPosition(position - 1);
Node deleteNode = node.next; //待删除的节点
node.next = deleteNode.next;
return true;
}
(2)根据值删除
public boolean removeByValue(int value){
Node pre = head;
Node current = head.next;
while (current != null){
if (current.data == value){
break;
}
pre = current;
current = current.next;
}
// 循环结束都没有找到,不存在待删除的value
if (current == null){
return false;
}
// 删除 current节点
pre.next = current.next;
return true;
}
5.其他辅助操作
/**
* 判断链表是否为空
* @return
*/
public boolean isEmpty(){
return head.next == null;
}
/**
* 获取链表长度
* @return
*/
public int getLength(){
Node tmpHead = head;
int len = 0;
while (tmpHead.next != null){
// 如果存在下一个节点
len ++;
tmpHead = tmpHead.next; // 到下一个节点
}
return len;
}