链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
单向链表,它包含两个域,一个信息域和一个指针域。信息域用来存储链表中要存放的值,指针域则指向下一个节点。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。其结构图如下:
双向链表在单链表的基础上,每个节点新增了一个指针域,用来指向前一个节点。其结构图如下:
首先创建一个LinkedList类。
创建一个ListNode类,包含两个属性,一个为链表节点的值,另一个为下一个节点的地址。
创建size属性记录链表长度
public class LinkedList {
//定义节点
static class ListNode {
int val; // 链表存储的值
ListNode next; // 指针,指向下一个节点
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
int size; // 链表长度
ListNode headNode; //链表头结点
ListNode dummyHead = new ListNode(0);
}
头插法,即在链表首部添加一个节点作为新的头结点。
首先要新建一个ListNode 对象作为要插入的节点,然后根据情况进行操作。如果当前链表为空链表,则将该节点直接作为头结点即可创建一个链表;如果当前链表不是空链表,则将要插入的节点的next指针指向原本的头节点。
public void headInsertion(int val) {
ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
newListNode.val = val; // 对节点存入要插入的值
if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
headNode = newListNode;
} else {
newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
headNode = newListNode; // 插入后新插入的节点是新的头结点
}
size ++;
}
insert方法为在任意位置插入节点,参数中的index为插入节点的位置,val为插入节点的值,如果index等于0,则和头插法过程相同。否则,需要先找到前一个节点, 将该节点的next指针指向前一个节点next指向的节点,然后再将前一个节点指向该节点。
插入过程图解如下:
(1)创建要插入的节点对象
(2)current节点指向next节点
(3)previous节点指向current节点,完成插入
public void insert(int index, int val) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
newListNode.val = val;
if (index == 0) { // 插入到第0位,和头插法相同
if (headNode == null) {
headNode = newListNode;
} else {
newListNode.next = headNode;
headNode = newListNode;
}
size ++;
} else {
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < index-1; i++) {
prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
}
newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
size ++;
}
}
先找到原先最后一个节点,然后将其next指向要插入的节点即可。
public void tailInsertion(int val) {
ListNode newListNode = new ListNode();
newListNode.val = val;
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < size-1; i++) {
prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
}
newListNode.next = prevNode.next;
prevNode.next = newListNode;
size ++;
}
找到第index-1个节点,将其直接指向第index+1个节点即可。需要注意空链表或者越界情况。
删除过程图解如下:
(1)找到要删除的节点对象current
(2)previous指针指向next节点即可删除。
public void deleteByIndex(int index) {
if (index > size) {
System.out.println("越界");
return;
}
if (headNode == null) {
System.out.println("空链表");
} else {
if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
headNode = headNode.next;
size --;
} else {
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < index-1; i++) {
prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
}
System.out.println("delete:"+prevNode.next.val);
// 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
prevNode.next = prevNode.next.next;
size --;
}
}
}
删除值为val的节点,以此遍历找到值为val的节点,并对其删除即可。
public void deleteByValue(int val) {
if (headNode == null) {
System.out.println("空链表");
} else {
while(val == headNode.val){// 如果头结点是要删除的元素
headNode = headNode.next;
size --;
}
ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
ListNode currentNode = headNode; // 创建指针,指向被操作的节点
while(prevNode != null && currentNode != null){
if(currentNode.val == val) {
prevNode.next = currentNode.next;
size--;
} else {
prevNode = currentNode;
}
currentNode = currentNode.next;
}
}
}
遍历找到即可。
public void getElum(int index) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode currentNode = headNode;
for (int i = 0; i < index; i++) {
currentNode = currentNode.next;
}
int result = currentNode.val;
System.out.println(result);
}
找到第index节点,修改val即可。
public void update(int index, int val) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode currentNode = headNode;
for (int i = 0; i < index; i++) {
currentNode = currentNode.next;
}
currentNode.val = val;
}
// 创建一个链表 1->2
public void creatLinkList() {
ListNode node1 = new ListNode();
node1.val = 2;
ListNode node2 = new ListNode();
node2.val = 1;
node1.next = node2;
headNode = node1;
size++;
size++;
}
public void display(){
ListNode current = headNode;
while(current != null){
System.out.print(current.val);
if (current.next != null) {
System.out.print("->");
}
current = current.next;
}
System.out.println();
}
package linkedList;
public class SingleLinkedList {
//定义节点
static class ListNode {
int val; // 链表存储的值
ListNode next; // 指针,指向下一个节点
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
int size; // 链表长度
ListNode headNode; //链表头结点
// ListNode dummyHead = new ListNode(0);
public SingleLinkedList() {
headNode = null;
size = 0;
}
//头插法
public void headInsertion(int val) {
ListNode newListNode = new ListNode(); // 新建一个对象,即为要插入的节点
newListNode.val = val; // 对节点存入要插入的值
if (headNode == null) { //头结点为空即是个空链表,头结点直接指向要插入的节点即可
headNode = newListNode;
} else {
newListNode.next = headNode; // 要插入的节点应放在第一个,所以它的下一个节点指向head
headNode = newListNode; // 插入后新插入的节点是新的头结点
}
size ++;
}
//头插法(使用虚拟头结点的方法)
// public void headInsertionVirtual(int val) {
// ListNode dummyHead = new ListNode(0, this.head);
// ListNode newListNode = new ListNode();
// newListNode.val = val;
// ListNode currentNode = dummyHead;
// currentNode.val = val;
// currentNode.next = dummyHead.next;
// size ++;
// }
//任意位置插入
public void insert(int index, int val) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode newListNode = new ListNode(); // 存放添加元素的链表节点
newListNode.val = val;
if (index == 0) { // 插入到第0位,和头插法相同
if (headNode == null) {
headNode = newListNode;
} else {
newListNode.next = headNode;
headNode = newListNode;
}
size ++;
} else {
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < index-1; i++) {
prevNode = prevNode.next; // 用该指针找到要添加元素位置的前一个
}
newListNode.next = prevNode.next; // 添加的节点的next指针指向要添加位置的下一个
prevNode.next = newListNode; //前一个节点的next指针指向添加的节点
size ++;
}
}
//尾插法
public void tailInsertion(int val) {
ListNode newListNode = new ListNode();
newListNode.val = val;
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < size-1; i++) {
prevNode = prevNode.next;// 用该指针找到要最后一个节点的前一个节点
}
newListNode.next = prevNode.next;
prevNode.next = newListNode;
size ++;
}
//删除第index个元素
public void deleteByIndex(int index) {
if (index > size) {
System.out.println("越界");
return;
}
if (headNode == null) {
System.out.println("空链表");
} else {
if (index == 0) { // 删除第一个元素,直接把头结点指向第二个元素即可
headNode = headNode.next;
size --;
} else {
ListNode prevNode = headNode; // 创建一个指向头结点的指针
for (int i = 0; i < index-1; i++) {
prevNode = prevNode.next; // 用该指针找到要删除元素位置的前一个
}
System.out.println("delete:"+prevNode.next.val);
// 要删除的元素的前一个节点的next指针指向下一个节点,完成删除
prevNode.next = prevNode.next.next;
size --;
}
}
}
//删除val元素
public void deleteByValue(int val) {
if (headNode == null) {
System.out.println("空链表");
} else {
while(val == headNode.val){// 如果头结点是要删除的元素
headNode = headNode.next;
size --;
}
ListNode prevNode = headNode; // 创建指针,指向被操作的节点的前一位
ListNode currentNode = headNode; // 创建指针,指向被操作的节点
while(prevNode != null && currentNode != null){
if(currentNode.val == val) {
prevNode.next = currentNode.next;
size--;
} else {
prevNode = currentNode;
}
currentNode = currentNode.next;
}
}
}
public void getElum(int index) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode currentNode = headNode;
for (int i = 0; i < index; i++) {
currentNode = currentNode.next;
}
int result = currentNode.val;
System.out.println(result);
}
public void update(int index, int val) {
if (index > size) {
System.out.println("越界");
return;
}
ListNode currentNode = headNode;
for (int i = 0; i < index; i++) {
currentNode = currentNode.next;
}
currentNode.val = val;
}
// 创建一个链表 1->2
public void creatLinkList() {
ListNode node1 = new ListNode();
node1.val = 2;
ListNode node2 = new ListNode();
node2.val = 1;
node1.next = node2;
headNode = node1;
size++;
size++;
}
//打印链表
public void display(){
ListNode current = headNode;
while(current != null){
System.out.print(current.val);
if (current.next != null) {
System.out.print("->");
}
current = current.next;
}
System.out.println();
}
public static void main(String[] args) {
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.creatLinkList();
singleLinkedList.headInsertion(5);
singleLinkedList.headInsertion(8);
singleLinkedList.headInsertion(9);
singleLinkedList.headInsertion(5);
singleLinkedList.display();
singleLinkedList.insert(0,3);
singleLinkedList.insert(0,3);
singleLinkedList.insert(2,3);
singleLinkedList.insert(2,3);
singleLinkedList.insert(2,7);
singleLinkedList.display();
singleLinkedList.tailInsertion(1);
singleLinkedList.display();
singleLinkedList.deleteByIndex(1);
singleLinkedList.display();
singleLinkedList.deleteByValue(3);
singleLinkedList.display();
singleLinkedList.getElum(0);
singleLinkedList.update(1, 6);
singleLinkedList.display();
}
}