链表(单链表)是一种通过指针将一组零散的内存块串联起来的数据结构,每个链表的结点除了存储的数据之外,还需要记录链上的下一个节点的地址
-
链表的插入和删除(给定节点指针)时间复杂度O(1),但遍历删除的时间复杂度是O(n)
-
双向链表:每个结点不止有一个后继指针指向后面的结点,还有一个前驱指针指向前面的结点。在删除指定指针指向的节点时,时间复杂度仅为O(1)若链表是有序链表,那么查找时可以向前向后遍历,平均能少遍历一半的数据
-
链表有关算法
-
单链表反转
定义两个节点curr,pre。curr.next指向pre,然后curr、pre后移一位,重复直到最后一个节点。 -
检测环
1.快慢指针,快指针每次走两步,慢指针每次走一步。相遇则说明有环
2.遍历链表并将节点值加入散列表中,若有重复的说明有环 -
有序链表合并
定义一个哨兵,每次加入较小节点,最后加入较长链表剩余部分 -
删除倒数第k个节点
定义快慢指针,从头节点开始快指针先走k-1步,然后快慢同时走,快指针走到表尾时慢指针指向的就是倒数第k个 -
求中间节点
快慢指针,快指针每次两步慢指针每次一步,快指针走到表尾慢指针指向中间节点 -
判断回文
快慢指针找到中点,慢指针移动过程中同时反转链表,然后从中点至两端一起移动并判断
-
链表Java实现
public class myLinkedlist {
public Node head;
public myLinkedlist() {
head = new Node(-1);
}
/**
* 将data加到链表尾部
*
* @param data
* @return
*/
public boolean append(int data) {
Node iter = head;
while (iter.next != null) iter = iter.next;
iter.next = new Node(data);
return true;
}
/**
* 将value插入到index之后
*
* @param index
* @return
*/
public boolean insertAfter(int index, int value) {
Node iter = head;
while (iter.data != index && iter.next != null) iter = iter.next;
if (iter.data != index && iter.next == null) {
System.out.println("链表中无对应节点!");
return false;
}
Node temp = iter.next;
iter.next = new Node(value);
iter.next.next = temp;
return true;
}
public boolean delete(int index) {
Node iter = head;
while (iter.next != null && iter.next.data != index) iter = iter.next;
if (iter.data != index && iter.next == null) {
System.out.println("链表中无对应节点!");
return false;
}
Node temp = iter.next.next;
iter.next = temp;
return true;
}
/**
* 反转链表
*/
public void reverse() {
Node iter = head.next;
if (iter.next == null)
return;
Node pre = iter;
Node mid = iter.next;
Node after = mid.next;
pre.next = null;
//after为null时说明mid是最后一个
while (after != null) {
//每次将mid指向pre
mid.next = pre;
pre = mid;
mid = after;
after = after.next;
}
mid.next = pre;
head.next = mid;
}
public boolean isPalindrome() {
if (head.next == null) {
System.out.println("链表为空!");
return false;
}
//只有两个节点
if (head.next.next.next == null) {
int first = head.next.data;
int second = head.next.next.data;
if (first == second)
return true;
else
return false;
}
Node fast;//快指针
Node slow;//慢指针
fast = slow = head.next;
int fStep;//快指针步数
int sStep;//慢指针步数
fStep = sStep = 0;
while (fast.next != null) {
fast = fast.next;
fStep++;
}
sStep = fStep / 2;
//慢指针向前移动,同时将单链表反转
Node pre, mid, after;
pre = slow;
mid = slow.next;
after = mid.next;
slow.next = null;
while (sStep > 0) {
mid.next = pre;
pre = mid;
mid = after;
after = after.next;
sStep--;
}
Node toStart, toEnd;
//奇数遍历起点
if (fStep % 2 == 1) {
toStart = pre;
toEnd = mid;
}
//偶数遍历起点
else {
toStart = pre.next;
toEnd = mid;
}
do {
if (toStart.data != toEnd.data)
return false;
toStart = toStart.next;
toEnd = toEnd.next;
} while (toStart != null && toEnd != null);
return true;
}
public String toString() {
StringBuilder builder = new StringBuilder();
Node iter = head;
int size = 0;
while (iter.next != null) {
builder.append(iter.next.data + ",");
size ++;
iter = iter.next;
}
return builder.toString() + " (size: " + size + ")";
}
public void linkedlistTest(){
myLinkedlist test = new myLinkedlist();
test.append(1);
System.out.println(test.toString());
test.delete(1);
System.out.println(test.toString());
test.append(2);
System.out.println(test.toString());
test.insertAfter(1,3);
System.out.println(test.toString());
test.delete(2);
System.out.println(test.toString());
test.append(4);
test.append(5);
test.append(6);
System.out.println(test.toString());
test.reverse();
System.out.println(test.toString());
test.reverse();
System.out.println(test.toString());
//测试是否为回文串
test.append(1);
test.append(2);
test.append(3);
test.append(2);
test.append(1);
System.out.println(test.isPalindrome());
}
}
class Node {
int data;
Node next;
protected Node(int data) {
this.data = data;
this.next = null;
}
}