node : 当前节点的地址
无头单向非循环链表
1、头插法
①判断是否为第一次插入 head == null ==> head = node
②第二次插入 node.next = head head = node
public void addFirst(int data) {
ListNode node = new ListNode(data);
//判断链表是否为空
if (this.head == null) {
this.head = node;
} else {
node.next = this.head;
this.head = node;
}
}
2、尾插法
①判断第一次插入 head == null ==> head = node
②找尾巴
③进行插入
public void addLast(int data) {
ListNode node = new ListNode(data);
ListNode tmp = this.head;
//判断链表是否为空
if (this.head == null) {
this.head = node;
} else {
//找最后一个节点
while(tmp.next != null) {
tmp = tmp.next;
}
tmp.next = node;
}
}
3、任意位置插入,第一个节点为0号下标
①首先判断index是否合法
②判断是否插入到第一个
③否的话 找到要插入节点的前一个位置,进行插入。 若插入到index位置,只需让头节点往后移index-1次就可以找到插入节点的前一个位置。
//得到链表长度
private int getlength() {
ListNode tmp = this.head;
int count = 0;
while(tmp != null) {
count++;
tmp = tmp.next;
}
return count;
}
//找要插入位置的前一个节点(index-1) 返回当前节点的引用
private ListNode findUpNode(int index) {
ListNode prev = this.head;
for (int i = 0; i < index-1; i++) {
prev = prev.next;
}
return prev;
}
public boolean addIndex(int index,int data) {
//首先判断index是否合法
if (index < 0 || index > getlength()) {
System.out.println("非法输入");
return false;
}
//判断是否插入到第一个
if (index == 0) {
addFirst(data);
return true;
}
//否的话 找到要插入节点的前一个位置,进行插入
ListNode prev = findUpNode(index);
ListNode node = new ListNode(data);
node.next = prev.next;
prev.next = node;
return true;
}
4、查找是否包含key关键字在单链表中
public boolean contains(int key) {
ListNode tmp = this.head;
while(tmp != null) {
if (tmp.data == key) {
return true;
}
tmp = tmp.next;
}
return false;
}
5、删除第一次出现的关键字key的节点
①找到删除节点的前驱 找到要删除的节点
②进行删除
③删除节点如果是头节点
//找要删除节点的前驱
public ListNode findPrevNode(int key) {
ListNode prev = this.head;
while (prev.next != null) {
if (prev.next.data == key) {
return prev;
}
prev = prev.next;
}
return null;
}
public void remove(int key) {
//删除的如果是头节点
if(this.head.data == key) {
this.head = this.head.next;
return;
}
//找到删除的节点的前驱 如果找不到 返回null
ListNode prev = findPrevNode(key);
if (prev == null) {
System.out.println("找不到");
return;
}
ListNode del = prev.next;
prev.next = del.next;
}
6、删除所有值为key的节点
定义两个临时节点prev tmp 向后运动
//删除所有值为key的节点
public void removeAllKey(int key) {
ListNode prev = this.head;
ListNode cur = this.head.next;
while(cur != null) {
if (prev.next.data == key) {
prev.next = cur.next;
cur = cur.next;
} else {
prev = cur;
cur = cur.next;
}
}
//处理第一个节点--最后处理
if (head.data == key) {
head = head.next;
}
}
7、得要单链表的长度
public int getlength() {
ListNode tmp = this.head;
int count = 0;
while(tmp != null) {
count++;
tmp = tmp.next;
}
return count;
}
7、打印单链表
判断cur是否为空,打印cur[data]
public void diaplay() {
if (this.head == null) {
return;
}
ListNode cur = this.head;
while(cur != null) {
System.out.printf(cur.data + " ");
cur = cur.next;
}
}
8、清空单链表
//清空单链表1
public void clear1() {
this.head = null;
}
//清空单链表2
public void clear() {
while (this.head.next != null) {
ListNode tmp = this.head.next;
this.head.next = tmp.next;
}
}
注意:
1、打印或者添加节点时注意空链表情况
2、移除数据时要处理头节点
3、清空时有两种方式
ps:如何查看内存泄漏
jps查看java进程号
jmap查看实例化进程的数量 查看内存泄漏并把结果重定向到文件夹中
双向链表
class ListNode {
public int data;
public ListNode next;
public ListNode prev;
public ListNode(int data) {
this.data = data;
}
}
public class DoubleList {
public ListNode head;
public ListNode last;//尾巴
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);
//第一次插入
if (this.head == null) {
this.head = node;
this.last = node;
} else {
node.next = this.head;
this.head.prev = node;
this.head = node;
}
}
//尾插法
public void addLast(int data) {
ListNode node = new ListNode(data);
//第一次插入
if (this.head == null) {
this.head = node;
this.last = node;
} else {
this.last.next = node;
node.prev= this.last;
this.last = node;
}
}
//显示
public void disPlay() {
if (this.head == null) {
return;
}
ListNode cur = this.head;
while (cur != null) {
System.out.print(cur.data +" ");
cur = cur.next;
}
System.out.println();
}
//index位置插入
private ListNode searchIndex(int index) {
ListNode cur = this.head;
for (int i = 0; i < index; i++) {
if (index < 0 || index >= size()) {
return null;
}
cur = cur.next;
}
return cur;
}
//任意位置插入,第一个数据节点为0号下标
public boolean addIndex(int index,int data) {
if (index == 0) {
addFirst(data);
return true;
}
if (index == size()) {
addLast(data);
return true;
}
//中间插入
ListNode node = new ListNode(data);
ListNode cur = searchIndex(index);
if (cur == null) {
return false;
}
cur.prev.next = node;
node.prev = cur.prev;
node.next = cur;
cur.prev = node;
return true;
}
public int size() {
ListNode cur = this.head;
int count = 0;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
// //查找是否包含关键字key是否在链表当中
public boolean contains(int key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.data == key) {
return true;
}
cur = cur.next;
}
return false;
}
//删除第一次出现关键字为key的节点
public void remove(int key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.data == key) {
//删除头节点
if (cur == this.head) {
this.head = this.head.next;
head.prev = null;
} else {
//删除中间节点
cur.prev.next = cur.next;
if (cur.next != null) {
cur.next.prev = cur.prev;
} else { //尾节点
this.last = cur.prev;
}
return;
}
cur = cur.next;
}
}
}
//删除所以出现关键字为key的节点
public void removeAllKey(int key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.data == key) {
//删除头节点
if (cur == this.head) {
this.head = this.head.next;
head.prev = null;
} else {
//删除中间节点
cur.prev.next = cur.next;
if (cur.next != null) {
cur.next.prev = cur.prev;
} else { //尾节点
this.last = cur.prev;
}
}
}
cur = cur.next;
}
}
//清空
public void clear() {
while (this.head != null) {
ListNode cur = this.head.next;
this.head.next = null;
this.head.prev = null;
this.head = cur;
// cur = cur.next;
}
this.last = null;
}
}