链表的节点
一个链表的节点(Node)分为两部分,第一部data分保存节点本身的数据,第二部分存储下一个节点地址。
最后一个节点存储的下一个节点的地址为空。单向链表,只提供从链表头插入节点。
使用内部类构造节点
private class Node{//使用内部类构造节点
private Object val;//节点数据
private Node next;//节点指针,指向下一个节点
public Node(Object val) {//构造方法赋值
this.val = val;
}
}
单向链表
- 链表的操作
- 1、插入节点
- 2、删除节点
- 如果是第一个节点,head指向后面一个节点
- 如果是最后一个节点,前一个节点的地址,改为null
- 如果是中间的节点,前一个节点地址,指向后一个节点。
public class SingleLinkedList {
private int size;//节点个数
private Node head;//头指针
private class Node{//使用内部类构造节点
private Object val;//节点数据
private Node next;//节点指针,指向下一个节点
public Node(Object val) {//构造方法赋值
this.val = val;
}
}
public Object addHead(int val) {//在链表头部添加新节点
Node node = new Node(val);//新建节点
if(head==null) {//如果头结点为空
head = node;//新节点就是头结点
}else {
node.next = head;//新节点的指针指向头结点
head = node;//新节点赋给头结点
}
size++;
return node.val;
}
public Object delHead() {
Object val = head.val;//存储头结点的值
head = head.next;//删除头结点
size--;
return val;
}
public Object find(Object obj) {
Node cur = head;
while(cur!=null) {
//如果当前节点不为空,并且不能要检索的值,一直向后遍历
if(obj.equals(cur.val)) {
return obj;
}else {
cur = cur.next;
}
}
return null;
}
public boolean delVal(Object val) {
Node delNode = head;//要删除的节点
// Node pre = head;//要删除节点的前一个节点
if(delNode==null) {//如果链表为空,返回false
return false;
}
while(delNode.next!=null) {//从第二个节点遍历
if(delNode.next.val==val) {
delNode.next = delNode.next.next;//删除节点
return true;
}else {
delNode = delNode.next;
if(delNode == null) {
break;
}
}
}
if(head.val==val) {//判断第一个节点,如果相等,删除
head = head.next;
return true;
}
return false;
}
public void print() {//打印链表
while(head!=null) {
System.out.print(head.val+",");
head = head.next;
}
}
}
双向链表
- 单向链表只能从一个方向遍历,双向链表可以从两个方向遍历。
- 双向链表的节点由三分部分组成:第一部分保存节点本身的数据,第二部分保存下一个节点的地址,第三部分保存上一个节点的地址。
public class DoubleLinkList {
/**
* 双向链表和单链表相似,只是多了一个后继指针
* 相比于单链表,只需要考虑链表为空时,头尾如何相连。
*/
private Node head;
private Node tail;
private int size;
class Node{
private Object val;//数据域
private Node prev;//前驱
private Node next;//后继
public Node(Object val) {
this.val = val;
}
}
public Object addHead(Object val) {
Node node = new Node(val);
if(head==null) {//如果头为空
tail = node;//将新节点赋给尾结点
}else {
head.prev = node;
node.next = head;
}
head = node;//头节点等于尾结点
return node.val;
}
public Object addTail(Object val) {
Node node = new Node(val);
if(head==null) {//如果链表为空
head = node;//将新节点赋给头结点
}else {
tail.next =node;
node.prev =tail;
}
tail = node;//尾结点等于头结点
return node.val;
}
public Object delHead() {
head = head.next;
return head.prev.val;
}
public Object delTail() {
tail = tail.prev;
return tail.next.val;
}
public void display() {
while(head!=null) {
System.out.println(head.val);
}
}
}
测试用例
public void display() {
while(head!=null) {
System.out.println(head.val);
}
}
public static void main(String[] args) {
DoubleLinkedList list = new DoubleLinkedList();
list.addHead(1);
list.addHead(2);
list.addHead(3);
list.addTail(4);
list.addTail(5);
list.addTail(6);
list.delHead();
list.delTail();
list.display();
}
总结:链表插入、删除效率特别高,主要应用于需要大量删除、插入的场景中。虽然相比于数组,占用空间稍大,但相比于数组存储数据需要一块连续的内存空间,链表可以利用碎片空间。怎么说那,各有各的优点和缺点吧。