本文是学习算法的笔记,《数据结构与算法之美》,极客时间的课程
写好链表代码
技巧一、理解指针或引用的含义
不管是C语言中指针的含义,还是JAVA语言中引用的概念,它们的意思是一样的,都是存储所指对象的内存地址。
编写链表代码的时候,这样的代码: p -> next=q。意思是p结点的next指针存储了q结点的内存地址。
还有更复杂的 p -> next = p -> next -> next。这个意思是p结点next指针存储了p结点下下琴结点的内存地址。
技巧二、警惕指针丢失和内存泄漏
p -> next = x; // 将 p 的 next 指针指向 x 结点;
x ->next = p -> next // 将 x 的结点的 next 指针指向 b 结点;
对于C 语言来说,这样会出现指针丢失,内存泄漏(x 结点的 next 指针指向了自己)
对于刚刚的插入代码,只需要把第1行和第2行顺序颠倒一下就可以了。
技巧三、利用哨兵简化实现难度
在链表的p结点后面插入一个新的节点,只需要两行代码就可以了
new_code -> next = p -> next;
p -> next = new_code;
当链表是空的,第一个节点插入是特殊的
if(head == null){
head = new_code;
}
类似的,删除一个节点
if(head -> next == null){
head = null;
}
针对链表的删除和插入操作,需要考虑第一个节点和最后一个节点的特殊情况,实现起来会有繁琐,有没有简洁的方法呢?
技巧三、引入哨兵
引入哨兵之后,不管链表是不是空链表,head指针都会一起指向哨兵节点。我们把这种链表叫做带头链表。同样,没有哨兵的叫不带头链表。
如图,有了哨兵节点后,插入删除操作可以用统一的代码实现了。
技巧四、留意边界的处理
比如链表为空、比如只包含一个结点或两个节点的情况。比如处理头结点和尾节点时,代码是否正确.
再就是 多写多练了,这里给出java语言实现的链表代码(这是我从课程的文本中复制出来的)
public class LinkedListDemo{
// 单链表反转
public static Node reverse(Node list) {
Node headNode = null;
Node previousNode = null;
Node currentNode = list;
while (currentNode != null) {
Node nextNode = currentNode.next;
if (nextNode == null) {
headNode = currentNode;
}
currentNode.next = previousNode;
previousNode = currentNode;
currentNode = nextNode;
}
return headNode;
}
// 检测环
public static boolean checkCircle(Node list) {
if (list == null)
return false;
Node fast = list.next;
Node slow = list;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast)
return true;
}
return false;
}
// 有序链表合并
public static Node mergeSortedLists(Node la, Node lb) {
if (la == null)
return lb;
if (lb == null)
return la;
Node p = la;
Node q = lb;
Node head;
if (p.data < q.data) {
head = p;
p = p.next;
} else {
head = q;
q = q.next;
}
Node r = head;
while (p != null && q != null) {
if (p.data < q.data) {
r.next = p;
p = p.next;
} else {
r.next = q;
q = q.next;
}
r = r.next;
}
if (p != null) {
r.next = p;
} else {
r.next = q;
}
return head;
}
// 删除倒数第K个结点
public static Node deleteLastKth(Node list, int k) {
Node fast = list;
int i = 1;
while (fast != null && i < k) {
fast = fast.next;
++i;
}
if (fast == null)
return list;
Node slow = list;
Node prev = null;
while (fast.next != null) {
fast = fast.next;
prev = slow;
slow = slow.next;
}
if (prev == null) {
list = list.next;
} else {
prev.next = prev.next.next;
}
return list;
}
// 求中间结点
public static Node findMiddleNode(Node list) {
if (list == null)
return null;
Node fast = list;
Node slow = list;
while (fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
public static void printAll(Node list) {
Node p = list;
while (p != null) {
System.out.print(p.data + " ");
p = p.next;
}
System.out.println();
}
public static Node createNode(int value) {
return new Node(value, null);
}
public static class Node {
private int data;
private Node next;
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
public int getData() {
return data;
}
}
}