前段时间知乎面试,面试官出了一道题目实现单链表的插入、删除、计算长度,当时勉强写出来了,但是不是用的面向对象的思路写的,面试官叫我改成面向对象的方式。当时突然想到AQS的底层实现方式,就想仿照改一下。结果面试官说时间原因,就不写了。。。。。
AQS里面有一个头结点head和一个尾节点tail,刚开始head和tail都是没有初始化的,后面第一个进入阻塞对的第一个节点会在enq方法中初始化head,AQS中阻塞队列是不算head节点,head节点可以理解为当前拥有锁的节点。想了解更多的可以去看看AQS和ReentrantLock的源码。
思想我们也可以借鉴AQS,实现一个带头结点的单链表(注意头结点是不算在链表中),具体的代码如下:
package cn.cqupt.linked;
class Node {
int data;
Node next;
Node() {
}
Node(int data) {
this.data = data;
this.next = null;
}
}
public class LinkedOp {
// 头结点
private Node head;
// 链表的长度
private int size;
// 构造函数初始化头结点,也可以在插入第一个节点的时候初始化
LinkedOp(){
head = new Node();
}
// 头插法
public void insertFromHead(int data){
// 将data封装为Node节点
Node node = new Node(data);
// 如果链表为空,直接跟在head后面
if(head.next == null){
head.next = node;
size++;
}else{
// 链表不为空,头插法插入节点
node.next = head.next;
head.next = node;
size++;
}
}
// 尾插法
public void insertFromLast(int data) {
Node node = new Node(data);
if (head.next == null) {
head.next = node;
size++;
} else {
// 这里要注意的是,while的判断是current.next是否为空
// 意思 就是current最后肯定是指向链表的最后一个节点
Node current = head.next;
while (current.next != null) {
current = current.next;
}
// 直接跟到最后
current.next = node;
// 长度+1
size++;
}
}
// 获取链表长度
public int getSize(){
return size;
}
// 删除节点
public void remove(int data) {
if (head.next == null){
System.out.println("当前链表为空");
return;
}
Node current = head;
while (current.next != null) {
if(current.next.data == data){
// current.next = current.next.next;
Node removeNode = current.next;
current.next = removeNode.next;
removeNode = null;//help GC
size--;
return;
}else{
current = current.next;
}
}
if(current.next == null){
System.out.println("该链表中没有这个节点");
}
}
// 删除指定下标的节点
public void removeIndex(int index){
if(index < 0 || index > size){
System.out.println("请输入正确的下标");
return;
}
if (head.next == null){
System.out.println("当前链表为空");
return;
}
int startIndex = 1;
Node current = head;
while(current.next != null && startIndex < index){
current = current.next;
startIndex++;
}
// 删除节点
Node removeNode = current.next;
current.next = removeNode.next;
removeNode = null;//help GC
size--;
}
// 遍历链表
public void printNode() {
if (head.next == null) {
System.out.println("链表为空!");
return;
}
Node current = head.next;
while (current.next != null) {
System.out.print(current.data + "--->");
current = current.next;
}
System.out.println(current.data);
System.out.println("链表长度为:"+size);
}
public static void main(String[] args) {
// 创建一个链表对象,创建时候会初始化头结点
LinkedOp link = new LinkedOp();
// 先打印链表
link.printNode();
// 头插法插入1、2
link.insertFromHead(1);
link.insertFromHead(2);
// 尾插法插入3、4
link.insertFromLast(3);
link.insertFromLast(4);
// 打印链表
link.printNode();
//System.out.println(link.getSize());
// 删除节点为4的
link.remove(4);
link.printNode();
// 删除第二个节点,节点从1开始
link.removeIndex(2);
link.printNode();
}
}

本文介绍了如何根据AQS(AbstractQueuedSynchronizer)的思想,实现一个带头结点的单链表,包括插入、删除和计算长度的功能。文章起源于作者在知乎面试中遇到的题目,原本的解决方案并非面向对象,后来尝试将其转换为面向对象的设计,虽然面试未完成,但作者分享了仿照AQS实现链表的代码。

4496

被折叠的 条评论
为什么被折叠?



