链表采用一组地址任意的存储单元存放线性表中的数据元素。
链式结构的线性表不会按线性的逻辑顺序来保持数据元素,它需要在每一个数据元素里保持一个引用下一个数据元素的引用。
单链表:
1.删除链表中固定节点的值
/**
* @author: ChangYajie
* @date: 2019/8/17
*
* 删除链表中等于给定值 val 的所有节点。
* 示例:
* 输入: 1->2->6->3->4->5->6, val = 6
* 输出: 1->2->3->4->5
*
*/
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public class Solution1 {
public ListNode remove(ListNode head,int val){
//设置虚拟头结点
ListNode dummyHead = new ListNode(-1);
//将虚拟头结点的引用指向链表头部
dummyHead.next = head;
//保存一个虚拟头结点的引用
ListNode prev = dummyHead;
while (prev.next != null){
if (prev.next.val == val){
prev.next = prev.next.next;
}else {
prev = prev.next;
}
}
return dummyHead.next;
}
}
2.反转单链表
/**
* @author: ChangYajie
* @date: 2019/8/17
* 反转一个单链表。
* 示例:
* 输入: 1->2->3->4->5->NULL
* 输出: 5->4->3->2->1->NULL
*
*/
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
//迭代
blic class Solution {
public ListNode reverseList(ListNode head){
ListNode dummy = new ListNode(-1);
dummy.next = head;
//当前需要移动的元素的前驱
ListNode pre = head;
while (pre != null && pre.next != null){
//当前要插入到头部的元素
ListNode curr = pre.next;
//将当前元素的前驱指针指向后继
pre.next = pre.next.next;
//当前元素的next指针指向头部
curr.next = dummy.next;
//修正虚拟头部指针指向
dummy.next = curr;
}
return dummy.next;
}
}
3.有序链表的合并
/**
* @author: ChangYajie
* @date: 2019/8/18
*
* 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
*
* 示例:
*
* 输入:1->2->4, 1->3->4
* 输出:1->1->2->3->4->4
*
*/
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//类似归并排序的合并过程
ListNode dummyHead = new ListNode(-1);
//cur在算法结束是不再指向链表的头部,所以一开始需要有dummyHead来保留对链表头部的引用
ListNode cur = dummyHead;
while (l1 != null && l2 != null){
if (l1.val < l2.val){
cur.next = l1;
cur = cur.next;
l1 = l1.next;
}else{
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
if (l1 == null){
cur.next = l2;
}else {
cur.next = l1;
}
return dummyHead.next;
}
}
4.返回链表的倒数第k个节点
/**
* @author: ChangYajie
* @date: 2019/8/18
* 返回链表的倒数第k个节点
*/
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
//第一个指针先走k-1步,第二个指针开始走,当第一个指针走到最后,第二个指针所在的位置就是第k个位置
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head == null || k <= 0){
return null;
}
ListNode slow = head;
ListNode fast = head;
for (int i = 1;i < k;i++){
//k比链表的长度大
if (fast.next == null){
return null;
}
//快指针先走
fast = fast.next;
}
//快指针走了k-1步后,俩个指针同时开始走
while (fast.next != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
5.链表的回文结构
/**
* @author: ChangYajie
* @date: 2019/8/18
*
* 判断链表是否是回文:
* 1-2-2-1
*
*/
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
//将链表A反转,判断反转后的链表与A链表是否相同,相同的即是回文
public class PalindromeList {
public boolean chkPalindrome(ListNode A) {
ListNode B = reverseList(A);
while (A != null){
if (A.val != B.val){
return false;
}
A = A.next;
B = B.next;
}
return true;
}
public ListNode reverseList(ListNode head){
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = head;
while(head != null && head.next != null){
//当前要插入到头部的数据
ListNode curr = pre.next;
pre.next = pre.next.next;
curr.next = dummy.next;
dummy.next = curr;
}
return dummy.next;
}
}