一.定义单链表结点
首先呢我们先得定义单链表中的每个节点,最后再定义一个头节点,作为单链表的开头。
class Node {
public int data;
public Node next;
public Node(int data) {
this.data = data;
}
}
public class MyLinedList {
public Node head;
public MyLinedList() {
this.head = null;
}
}
单链表中每个节点所存储的数据,指向下个结点的引用,都需要定义出来,其中Node就是引用类型,下来用构造方法对其进行数据初始化,由于我们并不知道我们定义的引用类型到底是什么,所以不需要对其进行初始化。最后呢,我们定义表头,也是Node类型,将他置为null,这里不需要置为null也是没有什么问题的,本来就是为空。
二.头插法
定义好单链表结构后,接下来,我们就来看,单链表的第一种创建方法:头插法。
public void addFirst(int data) {
Node node = new Node(data);
if (this.head == null) {
this.head = node;
return;
}
node.next = this.head;
this.head = node;
}
头插法就是每次都把要插入的节点插在已存在结点的前面。首先我们需要传入要插入的节点的数据data,接下来呢,我们需要确定当前单链表是不是为空,为空的话,说明当前结点是第一个结点,就直接让定义好的头结点head指向该结点就好了,然后返回该单链表。若不是第一次插入,则我们需要将要插入节点的next指向当前的head,然后将新的head指向当前的node就行了。
三.尾插法
创建单链表的第二种方法就是尾插法。
public void addLast(int data) {
Node node = new Node(data);
if (this.head == null) {
this.head = node;
return;
}
Node cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
尾插法呢就是每次插入到已有结点的后面。依然需要传入所插结点的数据,判断是否是第一次插入结点,第一次直接把head指向node就行了,若不是第一次,则首先我们先得找到当前链表的最后一个结点,定义cur指向head然后开始遍历,循环终止条件就是cur的next为空,这时cur就是最后一个结点,然后把cur的next指向node就行了。
四.任意位置插入结点
public void addIndex(int index, int data) {
if (index < 0 || index > size()) {
System.out.println("位置不合法");
return;
}
if (index == 0) {
addFirst(data);
return;
}
if (index == size()) {
addLast(data);
return;
}
int count = 0;
Node node = new Node(data);
Node prev = this.head;
while (count < index - 1) {
prev = prev.next;
count++;
}
node.next = prev.next;
prev.next = node;
}
public int size() {
Node cur = this.head;
int count = 0;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
传入参数要插入的位置和插入节点的数据。首先我们得考虑插入位置是否合法,就是说如果插入位置小于0或者超过该结点的长度,都是不合法的,直接return 就行。若等于0或者等于该链表长度,其实对应的就是头插法和尾插法。当插入位置在中间时,我们就需要在该位置的前后两个结点动手脚,首先呢我们就需要找到插入位置的前一个结点,定义prev指向head,然后遍历走index-1步,此时prev就是指向插入位置的前一个结点,此时还需要注意是先改变前面的结点还是后面的结点,如果先让prev的结点的next指向node,这时当node的next指向prev.next结点时,prev.next已经是node,所以无法实现连接,所以我们需要将这两个步骤颠倒,就可以了。
五. 删除第一次出现关键字为key的节点
public void remove(int key) {
if (this.head.data == key) {
this.head = this.head.next;
return;
}
Node prev = this.head;
// Node prev = findPrev(key);
while (prev.next != null) {
if (prev.next.data == key) {
prev.next = prev.next.next;
return;
}
prev = prev.next;
}
System.out.println("节点不存在");
}
首先我们得判断头结点是不是我们要删除的结点,是的话,我们就得令head指向当前head的下一个结点,如果不是,则我们定义prev从head.next开始遍历,如果遇到要删除的结点,直接让他指向prev的下下个结点就好了,因为prev是要删除结点的前一个结点,如果还没有找到,则直接返回要删除的结点不存在。
六.删除所有值为key的节点
public void removeAllKey(int key) {
Node prev = this.head;
Node cur = this.head.next;
while (cur != null) {
if (cur.data == key) {
prev.next = cur.next;
cur = cur.next;
} else {
prev = cur;
cur = cur.next;
}
}
if (this.head.data == key) {
this.head = this.head.next;
}
}
依然呢,我们需要考虑要删除的结点是头结点,这是就把head指向下一个结点就好了。此时呢我们需要设置两个prev和cur,一个指向head,一个指向head.next,prev的作用呢就是相当于每次要删除结点的前一个结点,cur是作为判断当前是否是要删除结点,这要操作起来也会方便点。这是我们需要考虑要删除的结点是不是连着的,如果是连着的,就prev的next指向cur的next,然后让cur往后走继续删除结点。如果不连着,就prev往后走一步,cur也走一步判断是否为删除结点。
今天就到这里,之后会出来一些面试题中的一些单链表题。@-@