卷
目录
《学习笔记》--温故而知新
从基础开始复习以前学过的 Java 基础,再一次的学习每天的学习都会对 Java 基础有着比以前更加深刻的理解,也会回顾起已经忘记了的Java基础的知识点。
一、链表是什么?
在我的认知里面,链表就是一根链子,就好比一个个的铁圈中间用铁丝连成了一个链子。链表也就像这样,它的每一个节点就好比一个铁圈,他们是非连续的,但是他们又能找到下一个节点在哪里。
官方一点的解释就是: 链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表中的 指针链 接 次序实现的 。
这是较为书面的解释,这里我画个图解释一下:
二、单向链表
1.如何创建链表的结构
代码如下(示例):
val 用来存储节点的值,next 用来存储下一个节点的地址值。
class oneListNode {
int val;
oneListNode next;
oneListNode(){}
oneListNode(int val){
this.val = val;
}
}
2.实现单链表的添加节点(尾部添加)
代码如下(示例):
//添加节点(尾部添加)
public static oneListNode found(oneListNode head,int val){
oneListNode node = new oneListNode(val);
if (head == null){
head = node;
return head;
}
oneListNode tail = head;
while ( tail.next != null){
tail = tail.next;
}
tail.next = node;
N++;
return head;
}
这里面的思想就是:先要进行头结点的判断,当头结点为空的时候,我们需要创建一个新的节点来当我们的头结点然后将其返回去。接下来也就是第二次添加节点【这里要注意我们要一直使用一个节点对象,途中要是有创建新的节点对象的话,会发生一点小错误(这里面也是我代码书写不规范所导致的)】,所以这时候我们的头结点对象就不为空了。这时候我们就要用一个临时的指针【也可以看成指针,虽然Java里面没有指针,但是指针的思想是不可能从数据结构中剔除的】,用这个指针【此时的指针就是指向我们的链表头,也就是此时的临时指针就是我们的头结点】去循环遍历找到我这个单列表的最后一个位置,然后往我这个最后的位置添加我们新的节点。
3.指定位置插入节点(已解决头节点插入)
插入的话有俩种思想:我的代码使用的是第一种思想
- 第一种:就是在节点5的位置插入,我要把节点5的节点变成我刚刚插入节点。
- 第二种:就是在节点5的位置插入,我要把节点5的节点之后的节点变成我刚刚插入节点。
//插入节点 指定位置插入
public static oneListNode insert(oneListNode head,int index,int val){
if (index <= 0){
System.out.println("输入不合法");
return null;
}
if (index > N){
System.out.println("添加位置超过链表长度,已在最后位置添加");
oneListNode found = found(head, val);
return found;
}
oneListNode pre = head;
oneListNode tail = null;
//头结点位置插入
if (index == 1){
oneListNode node = new oneListNode(val);
node.next = pre;
head = node;
return head;
}
for (int i = 1; i < index - 1; i++) {
pre = pre.next;
}
tail = pre.next;
oneListNode node = new oneListNode(val);
pre.next = node;
node.next = tail;
N++;
return head;
}
节点插入的话无非就是三种情况:
第一种:插入的位置大于链表的长度【俩种解决方法:1.报错返回null。2.直接插入到最后一个位置。】,如果小于0的话就直接报错返回null
第二种:在头结点插入,我的新节点的下一个指向我原来的头结点,然后我就让我新的节点变成我的头结点。 这样的话就完成了我们的头结点插入。
第三种情况:在链表中间插入。首先我们要找到我们要插入位置的前一个节点,并记录下当前节点的下一个节点。让我的前一个节点的下一个指向我要插入的新节点,新节点的下一个指向我刚刚保存的当前节点的下一个节点。
4.删除指定位置的节点(头结点也可删除)
public static oneListNode deleted(oneListNode head,int index){
if (index > N || index <= 0){
return null;
}
oneListNode pre = head;
if (index == 1){
System.out.println("被删除的节点是:"+pre.val);
pre = pre.next;
head = pre;
return head;
}
for (int i = 1; i < index - 1; i++) {
pre = pre.next;
}
oneListNode tail = pre.next;
pre.next = tail.next;
N--;
System.out.println("被删除的节点是:"+tail.val);
return head;
}
我觉得删除节点要容易于插入节点删除节点就是直接把我删除的节点的前一个节点的指向直接指向我当前要删除节点的下一个节点。这样的话就没有人指向我当前这个节点了所以就相当于节点被删除了。头结点的删除就是,把头结点的下一个节点赋值成为头结点,这样的话不就相当于没有头结点了吗。
5.链表的反转(非递归版)
主要是递归的我不会,嘿嘿。
// 链表反转
public static oneListNode reversal(oneListNode head){
oneListNode pre = null;
oneListNode tail = null;
while (head != null){
tail = head.next;
head.next = pre;
pre = head;
head = tail;
}
return pre;
}
这个的思想也简单,就是用来个临时的指针来存放当前节点和下一个节点,将俩个节点之间的连接断开然后在重新指向(这次的指向就是和原来的相反了),然后就是将头结点后移动,让后一个节点成为头结点。如此循环执行到链表完全反转。
6.链表的查询
我感觉比较鸡肋,链表的优势就是在于插入和删除的效率高,查找的效率极低。
public static Integer search(oneListNode head,Integer index){
if (head==null){
return -1;
}else if (head.next == null){
return head.val;
}
oneListNode node = head;
Integer newIndex = 1;
while (newIndex < index && node != null){
node = node.next;
newIndex++;
}
return node.val;
}
这里的代码就不用多解释了,就是遍历找到节点,然后返回节点的值。
7.链表的修改
public static void revamp(oneListNode head,Integer index,Integer newVal){
if (head==null){
return ;
}else if (head.next == null){
head.val = newVal;
}
oneListNode node = head;
Integer newIndex = 1;
while (newIndex < index && node != null){
node = node.next;
newIndex++;
}
node.val = newVal;
}
就是在查询的基础上的一些小小的修改,查询是返回当前节点的值,修改不就是将该节点的值修改成要改变成的值。
三、完整代码示例
public class oneList {
public static int N = 0;
public static void main(String[] args) {
oneListNode node = null;
for (int i = 1; i <= 10; i++) {
node = found(node, i);
}
// revamp(node,5,100);
// System.out.println(search(node, 5));
// node = deleted(node,1);
// System.out.println(node.val);
node = insert(node, 11, 100);
System.out.println("该列表经过操作之后为:");
while (node != null){
System.out.print(node.val+",");
node = node.next;
}
// insert(node,0,100);
// System.out.println(length());
//
// oneListNode reversal = reversal(node);
// while (reversal != null){
// System.out.println(reversal.val);
// reversal = reversal.next;
// }
}
public static oneListNode deleted(oneListNode head,int index){
if (index > N || index <= 0){
return null;
}
oneListNode pre = head;
if (index == 1){
System.out.println("被删除的节点是:"+pre.val);
pre = pre.next;
head = pre;
return head;
}
for (int i = 1; i < index - 1; i++) {
pre = pre.next;
}
oneListNode tail = pre.next;
pre.next = tail.next;
N--;
System.out.println("被删除的节点是:"+tail.val);
return head;
}
//插入节点 指定位置插入
public static oneListNode insert(oneListNode head,int index,int val){
if (index <= 0){
System.out.println("输入不合法");
return null;
}
if (index > N){
System.out.println("添加位置超过链表长度,已在最后位置添加");
oneListNode found = found(head, val);
return found;
}
oneListNode pre = head;
oneListNode tail = null;
//头结点位置插入
if (index == 1){
oneListNode node = new oneListNode(val);
node.next = pre;
head = node;
return head;
}
for (int i = 1; i < index - 1; i++) {
pre = pre.next;
}
tail = pre.next;
oneListNode node = new oneListNode(val);
pre.next = node;
node.next = tail;
N++;
return head;
}
// 返回链表长度
public static int length(){
return N;
}
//添加节点(尾部添加)
public static oneListNode found(oneListNode head,int val){
oneListNode node = new oneListNode(val);
if (head == null){
head = node;
return head;
}
oneListNode tail = head;
while ( tail.next != null){
tail = tail.next;
}
tail.next = node;
N++;
return head;
}
// 链表反转
public static oneListNode reversal(oneListNode head){
oneListNode pre = null;
oneListNode tail = null;
while (head != null){
tail = head.next;
head.next = pre;
pre = head;
head = tail;
}
return pre;
}
public static Integer search(oneListNode head,Integer index){
if (head==null){
return -1;
}else if (head.next == null){
return head.val;
}
oneListNode node = head;
Integer newIndex = 1;
while (newIndex < index && node != null){
node = node.next;
newIndex++;
}
return node.val;
}
public static void revamp(oneListNode head,Integer index,Integer newVal){
if (head==null){
return ;
}else if (head.next == null){
head.val = newVal;
}
oneListNode node = head;
Integer newIndex = 1;
while (newIndex < index && node != null){
node = node.next;
newIndex++;
}
node.val = newVal;
}
}
class oneListNode {
int val;
oneListNode next;
oneListNode(){}
oneListNode(int val){
this.val = val;
}
}
总结
单链表是数据结构中较为重要的部分,同样也是在历年的笔试中频频出现。所有理解并能熟练的书写出单列表的代码,其中的增加,插入,删除这些黛米是必须要能熟练的书写。其他的实际上当你会了增加,插入,删除这三个以后都是小Case。最好是能够手写出来单列表及其重要的方法。大家千万不要学我这样写,最好把方法也都写在你自定义好的节点类里面!!!(后悔莫及,又懒得重写了)
祝大家早日理解单链表,也欢迎大家给我提出意见。
明天开始双链表!