结构
单链表结构如下:
我们知道数组是连续的存储空间;而链表不需要,因为有「指针」,它通过“指针”将一组零散的内存块串联起来使用 。当系统总容量 >100M;但是不连续,此时我们无法申请容量为 100M 的数组,但是链表可以。
一般我们习惯性的将第一个节点称为头结点,并不存储实际的内容;而最后一个节点叫尾节点,是指向一个空地址NULL。
头结点 VS 头指针
这里,会有一个头结点和头指针的概念:
单链表有带头节点和不带头节点两种:
“链表中第一个节点的存储位置叫做头指针”,如果链表有头结点,那么头指针就是指向头结点的指针。头指针所指的不存放数据元素的第一个节点称为「头结点」(头结点指向首元节点 )。头结点的数据域一般不存放数据(有些情况下也可存放链表的长度,用做监视哨等)存放第一个数据元素的节点称作第一个数据元素节点,或称为首元节点。
链表中第一个节点的存储位置叫做头指针,那么整个链表的存取就必须从头指针开始。
“链表中第一个结点的存储位置叫做头指针”,如果链表有头结点,那么头指针就是指向头结点数据域的指针。
头结点的特性:
- 头结点不是必须的
- 对在第一个元素节点前插入节点和删除第一个节点,其操作与对其他节点的操作统一了。
- 1.带头结点时 删除第1个结点(q指向的是头结点):q->next = a1->next; free(p); 删除第i个结点(i不等于1):q->next = ai->next;free(p); 2.不带头结点时 删除第1个结点时(q为空):L = a1->next; free(p); 删除第i个结点(i不等于1):q->next = p->next;free(p);
指针
在 Java 中没有指针这个说法,理解成引用就好了。
将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。
在实际写代码过程中,可能也是指针最容易出错。
单链表所有操作
了解了上面的基本概念,现在可以来写简单的单链表了,在实战中不断犯错,不断理解。
import java.util.Scanner;
/**
* 包含链表的基本操作,而且输出比较友好哦
*/
public class TestObject {
private Node head = new Node();//头节点,初始为一个空节点
private Node temp;//临时节点
//定义节点结构
static class Node {
private Node next;
private int data;
public Node(int data) {
this.data = data;
}
public Node() {
}
}
//辅助:遍历链表输出
public void print(String str) {
temp = head.next;//head 是头节点,不保存实际的数据
System.out.println(str+":");
while (temp != null) {
System.out.print(temp.data + "->");
temp = temp.next;
}
//最后一个节点指向 null
System.out.println("null");
}
//辅助:链表长度
public int length() {
temp = head.next;//我这直接从第一个真正存储元素的位置开始
int length = 1;
while (temp != null) {
length++;
temp = temp.next;
}
return length;
}
//初始化一个链表(每次都在链尾插入)
public void addNode(int data) {
Node newNode = new Node(data);//新节点的数据
temp = head;//每次从头节点开始遍历
// while 循环使得每次 temp 都会是当前链表的最后一个节点
while (temp.next != null) {
temp = temp.next;
}
//在链表的尾部增加一个节点
temp.next = newNode;
}
//指定位置插入
public void insertNode(int index, int data) {
if (index > length() || index < 0) {
System.out.println("插入位置错误," + "插入范围应为:" + "[1" + "," + length() + "]");
}
Node indexNode = new Node(data);
temp = head; //始终从头节点开始遍历
int length = 1;
/* while (temp != null) {
if (length == index)
break;
temp = temp.next;
length++;
}
//主要理解下面这两句代码
indexNode.next = temp.next;
temp.next = indexNode;*/
//两种方法都可以
while(temp != null) {
//注意 length++ 哦
if (length++ == index) {
//主要理解下面这两句代码
indexNode.next = temp.next;
temp.next = indexNode;
}
temp = temp.next;
}
}
//指定位置删除
public void deleteNode(int index){
if (index > length()-1 || index < 0) {
System.out.println("插入位置错误," + "插入范围应为:" + "[1" + "," + length() + ")");
}
temp=head;
int length=1;
while(temp!=null){
if(length++==index){
//将被删除的节点的 next指针 赋给它的前一个 next指针
temp.next=temp.next.next;
}
temp=temp.next;
}
}
public static void main(String[] args) {
TestObject test = new TestObject();
//初始化一个链表
int data[] = {1, 5, 3, 4, 6};
for (int i = 0; i < data.length; i++) {
test.addNode(data[i]);
}
//输出
test.print("初始化的链表");
Scanner insIn = new Scanner(System.in);
System.out.println("请输入要插入节点的位置:");
int index=insIn.nextInt();
System.out.println("请输入要插入节点的数据:");
//在指定位置插入节点 + 输出
test.insertNode(index,insIn.nextInt());
test.print("插入后的链表");
Scanner delIn = new Scanner(System.in);
System.out.println("请输入要删除节点的位置:");
//在指定位置删除节点 + 输出
test.deleteNode(delIn.nextInt());
test.print("删除后的链表");
}
}
下面示意图是在指定位置插入一个节点的详解;其他比如删除操作同理
总结
- 学会用画图辅助自己思考,可能有时候只靠想,脑子会不够用哦。
- 不要觉得自己看懂了,我要我觉得你应该去自己独立的写出来。
- 如果觉得自己代码没有问题,但是结果并不是自己想象那样的,那么请 Debug。IDEA Debug 了解一下。
### 文章目录
- [头结点 VS 头指针](https://editor.csdn.net/md/?articleId=103518330#_VS__8)
- [指针](https://editor.csdn.net/md/?articleId=103518330#_31)
- [单链表所有操作](https://editor.csdn.net/md/?articleId=103518330#_38)
- [总结](https://editor.csdn.net/md/?articleId=103518330#_176)
单链表结构如下:

我们知道数组是连续的存储空间;而链表不需要,因为有「指针」,它通过“指针”将一组零散的内存块串联起来使用 。当系统总容量 >100M;但是不连续,此时我们无法申请容量为 100M 的数组,但是链表可以。
一般我们习惯性的将第一个节点称为**头结点**,并不存储实际的内容;而最后一个节点叫**尾节点**,是指向一个空地址NULL。
# []()头结点 VS 头指针
这里,会有一个头结点和头指针的概念:
单链表有带头节点和不带头节点两种:
> “链表中第一个节点的存储位置叫做头指针”,**如果链表有头结点,那么头指针就是指向头结点的指针**。头指针所指的不存放数据元素的第一个节点称为「头结点」(头结点指向首元节点 )。头结点的数据域一般不存放数据(有些情况下也可存放链表的长度,用做监视哨等)存放第一个数据元素的节点称作第一个数据元素节点,或称为**首元节点**。
链表中第一个节点的存储位置叫做头指针,那么整个链表的存取就必须从头指针开始。
**“链表中第一个结点的存储位置叫做头指针”,如果链表有头结点,那么头指针就是指向头结点数据域的指针。**

**头结点的特性:**
- 头结点不是必须的
- 对在第一个元素节点前插入节点和删除第一个节点,其操作与对其他节点的操作统一了。
- 1.带头结点时
删除第1个结点(q指向的是头结点):q->next = a1->next; free§;
删除第i个结点(i不等于1):q->next = ai->next;free§;
2.不带头结点时
删除第1个结点时(q为空):L = a1->next; free§;
删除第i个结点(i不等于1):q->next = p->next;free§;
# []()指针
在 Java 中没有指针这个说法,理解成引用就好了。
**将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。**
在实际写代码过程中,可能也是指针最容易出错。
# []()单链表所有操作
了解了上面的基本概念,现在可以来写简单的单链表了,在实战中不断犯错,不断理解。
import java.util.Scanner;
/**
-
包含链表的基本操作,而且输出比较友好哦 */ public class TestObject { private Node head = new Node();//头节点,初始为一个空节点 private Node temp;//临时节点
//定义节点结构 static class Node { private Node next; private int data;
public Node(int data) { this.data = data; } public Node() { }
}
//辅助:遍历链表输出 public void print(String str) { temp = head.next;//head 是头节点,不保存实际的数据 System.out.println(str+":"); while (temp != null) { System.out.print(temp.data + "->"); temp = temp.next; } //最后一个节点指向 null System.out.println("null"); }
//辅助:链表长度 public int length() { temp = head.next;//我这直接从第一个真正存储元素的位置开始 int length = 1; while (temp != null) { length++; temp = temp.next; } return length; }
//初始化一个链表(每次都在链尾插入) public void addNode(int data) { Node newNode = new Node(data);//新节点的数据 temp = head;//每次从头节点开始遍历 // while 循环使得每次 temp 都会是当前链表的最后一个节点 while (temp.next != null) { temp = temp.next; } //在链表的尾部增加一个节点 temp.next = newNode; }
//指定位置插入 public void insertNode(int index, int data) { if (index > length() || index < 0) { System.out.println("插入位置错误," + "插入范围应为:" + "[1" + "," + length() + "]"); }
Node indexNode = new Node(data); temp = head; //始终从头节点开始遍历 int length = 1; /* while (temp != null) { if (length == index) break; temp = temp.next; length++; } //主要理解下面这两句代码 indexNode.next = temp.next; temp.next = indexNode;*/ //两种方法都可以 while(temp != null) { //注意 length++ 哦 if (length++ == index) { //主要理解下面这两句代码 indexNode.next = temp.next; temp.next = indexNode; } temp = temp.next; }
}
//指定位置删除 public void deleteNode(int index){ if (index > length()-1 || index < 0) { System.out.println("插入位置错误," + "插入范围应为:" + "[1" + "," + length() + ")"); }
temp=head; int length=1; while(temp!=null){ if(length++==index){ //将被删除的节点的 next指针 赋给它的前一个 next指针 temp.next=temp.next.next; } temp=temp.next; }
}
public static void main(String[] args) { TestObject test = new TestObject(); //初始化一个链表 int data[] = {1, 5, 3, 4, 6}; for (int i = 0; i < data.length; i++) { test.addNode(data[i]); } //输出 test.print("初始化的链表");
Scanner insIn = new Scanner(System.in); System.out.println("请输入要插入节点的位置:"); int index=insIn.nextInt(); System.out.println("请输入要插入节点的数据:"); //在指定位置插入节点 + 输出 test.insertNode(index,insIn.nextInt()); test.print("插入后的链表"); Scanner delIn = new Scanner(System.in); System.out.println("请输入要删除节点的位置:"); //在指定位置删除节点 + 输出 test.deleteNode(delIn.nextInt()); test.print("删除后的链表");
} }
> 下面示意图是在指定位置插入一个节点的详解;其他比如删除操作同理
> 
# []()总结
- 学会用画图辅助自己思考,可能有时候只靠想,脑子会不够用哦。
- 不要觉得自己看懂了,我要我觉得你应该去自己独立的写出来。
- 如果觉得自己代码没有问题,但是结果并不是自己想象那样的,那么请 Debug。[IDEA Debug](https://www.cnblogs.com/jajian/p/9410844.html) 了解一下。
Markdown 3600 字数 181 行数 当前行 1, 当前列 0
HTML 3023 字数 145 段落