链表
链表
本来关于链表是不准备写这个的,但是呢由于lxj和zyj,还是写一下吧,嗨,人生真难。
写在最前,由于最近在刷leetcode,所以🌰一半是从leetcode中的习题得来
单链表
单链表的定义以及基本操作
// 单链表
class Test{
// 链表节点类
public static class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val){this.val = val;}
ListNode(int val,ListNode next){this.val = val;this.next = next;};
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2);
ListNode l3 = new ListNode(3);
ListNode l4 = new ListNode(4);
ListNode l5 = new ListNode(5);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
printLinkedList(l1);
System.out.println(lenOfLinkedList(l1));
System.out.println(findNode(l1,3));
System.out.println(findNode2(l1,7));
printLinkedList(insertListNode(l1,3,9));
printLinkedList(deleteListNode(l1,5));
printLinkedList(reverse(l1));
}
// 打印整个链表
public static void printLinkedList(ListNode head){
if(head == null) return;
while(head!=null){
System.out.print(head.val + " ");
head = head.next;
}
System.out.println();
}
// 求链表长度
public static int lenOfLinkedList(ListNode head){
int res = 0;
while(head!=null){
res++;
head = head.next;
}
return res;
}
// 查找节点操作
// 按照位置进行查找
public static int findNode(ListNode head,int k){
if(head == null || lenOfLinkedList(head) < k) return 0;
while(k-->1) head = head.next;
return head.val;
}
// 按照值val进行查找
public static boolean findNode2(ListNode head,int val){
while(head!=null){
if(head.val == val) return true;
head = head.next;
}
return false;
}
// 插入节点
public static ListNode insertListNode(ListNode head,int k,int val){
if(head == null || lenOfLinkedList(head) < k) return head;
// 插入节点的关键在于记录插入位置前的那个节点,以及插入位置后的那个节点
ListNode dummy = new ListNode();
ListNode cur = head;
ListNode insertNode = new ListNode(val);
dummy.next = head;
// 找到插入节点的位置
while(k-->1) cur=cur.next;
// 插入节点
insertNode.next = cur.next;
cur.next = insertNode;
return dummy.next;
}
// 删除节点
public static ListNode deleteListNode(ListNode head,int val){
if(head == null) return head;
ListNode dummy = new ListNode();
dummy.next = head;
while(head!=null){
if(head.next!=null && head.next.val == val) head.next = head.next.next;
head = head.next;
}
return dummy.next;
}
// 原地翻转链表
public static ListNode reverse(ListNode head){
if(head == null || head.next == null) return head;
ListNode dummy = new ListNode();
ListNode cur = head;
ListNode nex = head.next;
while(cur!=null){
cur.next = dummy.next;
dummy.next = cur;
cur = nex;
if(nex!=null) nex = nex.next;
}
return dummy.next;
}
}
注:上述代码均通过测试
一般有关于单链表的题型
详情见另外一个博客,🔗如下
链表常见简单题型
双链表
双链表的定义以及基本操作
// 双链表
class Test{
static class ListNode{
int val;
ListNode pre;
ListNode next;
ListNode(){}
ListNode(int val){this.val=val;}
ListNode(int val,ListNode pre){this.val = val;this.pre = pre;}
ListNode(int val,ListNode pre,ListNode next){this.val = val;this.next = next;this.pre = pre;}
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2,l1);
ListNode l3 = new ListNode(3,l2);
ListNode l4 = new ListNode(4,l3);
ListNode l5 = new ListNode(5,l4);
ListNode l6 = new ListNode(6,l5);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
l5.next = l6;
printListNode(l1);
printListNode(insert(l1,3,9));
printListNode(delete(l1,9));
}
// 打印双向链表
public static void printListNode(ListNode head){
while(head!=null){
System.out.print(head.val+" ");
head=head.next;
}
System.out.println();
}
// 求长度
public static int len(ListNode head){
int res = 0;
while(head !=null){
res++;
head=head.next;
}
return res;
}
// 插入
public static ListNode insert(ListNode head,int k,int val){
if(head == null || len(head) < k) return head;
ListNode dummy = new ListNode();
dummy.next = head;
head.pre = dummy;
while(k-->1) head = head.next;
ListNode cur = new ListNode(val);
cur.next = head.next;
head.next.pre = cur;
head.next = cur;
cur.pre = head;
return dummy.next;
}
// 删除
public static ListNode delete(ListNode head,int val){
if(head == null) return head;
ListNode dummy = new ListNode();
dummy.next = head;
head.pre = dummy;
while(head!=null){
// 找到了要删除的节点,要删除的节点上一个节点是head
if(head.next!=null && head.next.val == val){
head.next = head.next.next;
head.next.next.pre = head;
break;
}
head= head.next;
}
return dummy.next;
}
}
注:上述代码均通过测试
一般有关于双向链表的题型
剑指 Offer 36. 二叉搜索树与双向链表
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
Node pre, head;
public Node treeToDoublyList(Node root) {
if(root == null) return null;
dfs(root);
head.left = pre;
pre.right = head;
return head;
}
void dfs(Node cur) {
if(cur == null) return;
dfs(cur.left);
if(pre != null) pre.right = cur;
else head = cur;
cur.left = pre;
pre = cur;
dfs(cur.right);
}
}
循环链表
循环单链表
// 循环单链表
class Test{
// 链表节点类
public static class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val){this.val = val;}
ListNode(int val,ListNode next){this.val = val;this.next = next;};
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2);
ListNode l3 = new ListNode(3);
ListNode l4 = new ListNode(4);
ListNode l5 = new ListNode(5);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
// 成为循环链表的重要操作
l5.next = l1;
}
}
循环双链表
class Test{
static class ListNode{
int val;
ListNode pre;
ListNode next;
ListNode(){}
ListNode(int val){this.val=val;}
ListNode(int val,ListNode pre){this.val = val;this.pre = pre;}
ListNode(int val,ListNode pre,ListNode next){this.val = val;this.next = next;this.pre = pre;}
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2,l1);
ListNode l3 = new ListNode(3,l2);
ListNode l4 = new ListNode(4,l3);
ListNode l5 = new ListNode(5,l4);
ListNode l6 = new ListNode(6,l5);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
l5.next = l6;
// 成为循环链表的操作
l6.next = l1;
l1.pre = l6;
}
}
一般有关于循环链表的题型
如上 剑指 Offer 36. 二叉搜索树与双向链表
静态链表
概念:
静态链表借助于数组来描述线性表的链式存储结构 ,节点也有数据域data和指针域next,与前面的所讲述的链表不同的是,这里的指针指向的节点的相对地址(数组的下标,又称为游标),和顺序表(数组)一样,静态链表也需要预先分配一块内存空间。一般而言,静态链表以\(next==-1\)结束。
Saying Less Doing More