赞
踩
链表是一种物理存储单元上非连续、非顺序,但在逻辑上是有顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
链表中的数据是以节点来表示的,每个节点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个节点的地址数据。
以“节点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。
存放节点值的数据域 | 存放节点的下一个节点的地址的链域 |
---|
data | next
data | next
以两个节点为例,假设第二个节点得地址是0x111,那么第一个节点的next存储得就是0x111,这样一次链接,就可以形成一个单链表,第一个节点是单链表得头节点用head标识,且最后一个节点得next为null.
class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
public class MyLinkedList { //创建单链表
public Node head = null;
//头插法
public void addFirst(int val) {
Node node = new Node(val);
node.next = this.head;
this.head = node;
}
public void addLast(int val) {
Node node = new Node(val);
if (this.head == null) {
this.head = node;
} else {
Node cur = this.head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
}
//任意位置插入,第一个数据为0号下标 public void addIndex(int index, int data) { //位置的合法性 if (index < 0 || index > getlength()) { System.out.println("插入的位置不合法!"); return; } if (index == 0) { addFirst(data); //头插法 return; } if (index == getlength()) { addLast(data); //尾插法 return; } //中间插入 Node ret = searchIndexSubOne(index); //ret 存储的是index-1位置的节点的 Node node = new Node(data); node.next = ret.next; ret.next = node; }
其中searchIndexSubOne(index)方法为找到要插入节点的前一个节点,具体的实现:
public Node searchIndexSubOne(int index) {
Node cur = this.head;
while (index - 1 != 0) {
cur = cur.next;
index--;
}
return cur;
}
public int getlength() {
int len = 0;
Node cur = this.head;
while (cur != null) {
len++;
cur = cur.next;
}
return len;
}
public boolean contains(int key) {
Node cur = this.head;
while (cur != null) {
if (cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}
public void remove(int key) {
if (this.head.val == key) {
this.head = this.head.next;
return;
}
//先找到前驱节点
Node pre = searchPrev(key);
if (pre == null) {
System.out.println("没有找到要删除的元素");
} else {
Node del = pre.next;
pre.next = del.next;
}
}
其中 searchPrev(key)方法是为了找到前驱节点,即要删除的前一个节点,具体的实现:
public Node searchPrev(int key) {
Node cur = this.head;
while (cur != null) {
while (cur.next.val == key) {
return cur;
}
cur = cur.next;
}
return null;
}
public void removeAllKey(int key) { Node cur = this.head.next; Node pre = this.head; while (cur != null) { if (cur.val == key) { pre.next = cur.next; cur = cur.next; } else { pre = cur; cur = cur.next; } } if (this.head.val == key) { this.head = this.head.next; } }
public void show() {
Node cur = this.head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
}
public Node reverseList() { if (this.head == null && this.head.next == null) { return null; } Node cur = this.head; Node curNext = this.head.next; cur.next = null;// 如果没有将第一个next清除就会变成循环 cur = curNext; while (cur != null) { curNext = curNext.next; cur.next = this.head; this.head = cur; cur = curNext; } return this.head; }
//快慢指针法 来找中间节点
public int middleNode() {
if (this.head == null) {
return this.head.val;
}
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) { //用&&来区分奇偶情况,满足其中一个情况就结束;
// 偶节点fast=null ;奇节点fast.next=null停止
fast = fast.next.next;
slow = slow.next;
}
return slow.val;
}
public Node ringEntrance() { Node fast = this.head; Node slow = this.head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if (fast == slow) { break; } } if (fast == null || fast.next == null) { return null; } slow = this.head; while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; }
public boolean hasCycle() {
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
if (fast == null || fast.next == null) {
return false;
}
return true;
}
public boolean chkPalindrome() { if (this.head == null) { return false; } if (this.head.next == null) { return true; } Node fast = this.head; Node slow = this.head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } //翻转从中间节点起后面的节点 三个变量 Node cur = slow.next; while (cur != null) { Node curNext = slow.next; cur.next = slow; slow = cur; cur = curNext; } while (this.head != slow) { //奇数情况 if (this.head.val != slow.val) { return false; } //偶数情况 if (this.head.next == slow) { return true; } this.head = this.head.next; slow = slow.next; } return true; }
public Node deleteDuplication() { Node cur = this.head; Node tmpHead = new Node(-1); Node newHead = tmpHead; while (cur != null) { if (cur.next != null && cur.val == cur.next.val) { while (cur.next != null && cur.val == cur.next.val) { cur = cur.next; } cur = cur.next; } else { tmpHead.next = cur; tmpHead = tmpHead.next; cur = cur.next; } } tmpHead.next = null; return newHead.next; }
public Node partition(int x) { Node cur = this.head; Node bs = null; //将节点分为两部分大于x 和小于等于x Node be = null; // bs表示大于x节点的头部(开始) be表示大于x节点的尾部 Node as = null; //as表示小于等于x节点的头部(开始) ae表示小于等于x节点的尾部 Node ae = null; while (cur != null) { if (cur.val < x) { //大于x if (bs == null) { bs = cur; be = bs; } else { be.next = cur; be = be.next; } //小于等于x } else { if (as == null) { as = cur; ae = as; } else { ae.next = cur; ae = ae.next; } } cur = cur.next; } if (bs != null) { this.head = bs; be.next = as; } else { this.head = as; } if (ae != null) { ae.next = null; } return this.head; }
思路:快慢指针 快指针先走k-1步 ;慢指针再走,就会相差k-1步,相差k个节点,当快指针走到最后一个节点是,慢指针刚好到k;
public Node FindKthToTail(int k) { if (head == null) { return null; } if (k <= 0) { return null; } Node fast = this.head; Node slow = this.head; while (k - 1 != 0) { if (fast.next != null) { //这注意!!防止空指针 fast = fast.next; k--; } else { System.out.println("给的k值太大"); return null; } while (fast.next != null) { fast = fast.next; slow = slow.next; } } return slow; } }
链表的问题需要逻辑严谨,不断地修改调试,代码太多debug找错点也很困难,需要反复实践,找到最快的断点来找出bug
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。