前言
链表:一种在物理上非连续、非顺序的数据结构,由若干节点所组成。
链表常用的有单向链表和双向链表,链表的第一个节点称为头节点,最后一个节点称为尾节点,尾节点的next指针指向空:
另外,数组在内存中的存储方式是顺序存储,而链表在内存中的存储方式是随机存储。
下面采用java代码对链表实现以下操作:
- 查找节点
- 更新节点
- 插入节点
- 删除元素
代码实现
package 第二章;
public class No2_2 {
/**
* 节点类,data:节点中的数据;next:指向下一个节点的指针next
*/
private static class Node{
int data;
Node next;
// 初始化函数
public Node(int data){
this.data = data;
}
}
static class MyLinkedList{
// 创建头节点指针
private Node head;
// 创建尾节点指针
private Node last;
// 链表的实际长度
private int size;
/**
* 插入函数
* @param data 要插入的数据
* @param index 要插入的位置
* @throws Exception
*/
public void insert(int data, int index) throws Exception{
if (index < 0 || index > size){
throw new IndexOutOfBoundsException("超出链表节点范围");
}
// 创建插入节点,将data作为参数初始化节点
Node insertNode = new Node(data);
if (size == 0){
// 若链表为空,将插入节点作为头节点和尾节点
head = insertNode;
last = insertNode;
}else if (index == 0){
// 若插入的位置是头部
insertNode.next = head;
head = insertNode;
}else if (size == index){
// 若插入的位置是尾部
last.next = insertNode;
last = insertNode;
}else{
// 若插入的位置是中间
// 先得到该位置的前一个节点
Node prevNode = query(index-1);
// 将插入节点的指针指向要插入位置的节点
insertNode.next = prevNode.next;
// 将前一个位置节点的指针指向插入节点
prevNode.next = insertNode;
}
// 插入之后,链表大小+1
size++;
output();
}
/**
* 查找函数
* @param index 要查找的元素的位置
*/
public Node query(int index) throws Exception{
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
// 创建一个中间节点,并指向头节点
Node temp = head;
for(int i=0;i<index;i++){
// 遍历链表,每次将当前节点指向的节点赋值给temp
temp = temp.next;
}
System.out.println("节点查询成功");
return temp;
}
/**
* 删除节点
* @param index 要删除的位置
* @throws Exception
*/
public void delete(int index) throws Exception{
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
if (index == 0){
// 删除头节点
head = head.next;
}else if (index == (size-1)){
// 删除尾节点
Node prevNode = query(index-1);
// 首先把尾节点的前一个节点的指针指向空
prevNode.next = null;
// 然后将该节点赋值给尾节点
last = prevNode;
}else{
Node prevNode = query(index-1);
// 将前一个节点的指针指向下下个节点
prevNode.next = prevNode.next.next;
}
System.out.println("节点删除成功");
size--;
output();
}
/**
* 更新节点数据
* @param data 要更新的数据
* @param index 要更新的位置
* @throws Exception
*/
public void updata(int data, int index) throws Exception{
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("超出链表节点范围!");
}
Node node = query(index);
node.data = data;
System.out.println("节点数据修改成功");
output();
}
/**
* 输出链表
*/
public void output(){
Node temp = head;
for (int i=0;i<size; i++){
System.out.println("第" + (i+1) + "个节点:" + temp.data);
temp = temp.next;
}
System.out.println("==========================");
}
}
public static void main(String[] args) throws Exception{
MyLinkedList myLinkedList = new MyLinkedList();
// 插入节点
myLinkedList.insert(3,0);
myLinkedList.insert(4, 1);
myLinkedList.insert(9,2);
myLinkedList.insert(7,3);
myLinkedList.insert(5,4);
// 查询节点
Node temp = myLinkedList.query(1);
System.out.println("该节点数据为" + temp.data);
// 更新节点
myLinkedList.updata(2,3);
// 删除节点
myLinkedList.delete(2);
}
}
小结
链表和数组都是线性的数据结构。
数组的优点在于能够快速定位元素,适合对于读操作多,写操作较少的场景。
链表的优点在于能够灵活地进行插入和删除操作,适合需要在尾部频繁插入或者删除元素的场景。