单链表与双链表
单链表:两个属性分别为值,和下一个节点的地址
双链表:三个属性分别为值,上一个节点的地址和下一个节点的地址
题目一:单链表的反转
public class reverseLinkedList {
public static class Node {
public int vaule;
public Node next;
public Node(int vaule) {
this.vaule = vaule;
}
}
static Node reverseLinkedList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
//如果仅像下面这样操作,head的vaule还是1,因为引用的传递,在上面的reverseLinkedList方法中如果在head = next;后面对head的属性进行操作,改变的实际是next的属性,因为head指向next
//reverseLinkedList(head);
//System.out.println(head.vaule);//head.vaule=1
head = reverseLinkedList(head);
System.out.println(head.vaule);
System.out.println(head.next.vaule);
System.out.println(head.next.next.vaule);
}
}
JVM的释放:在上面这种链表中,只有一个对象head,如果先改变了head的指向,而不改变head,原先head的所有指向都会消失,这叫做JVM的释放
题目二:双链表的反转
public class reverseDoubleList {
public static class Node {
public int vaule;
public Node next;
public Node last;
public Node(int vaule) {
this.vaule = vaule;
}
}
static Node reverseDoubleList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
//记录下一个位置
next = head.next;
//改变head的last
head.last = next;
//改变head的next
head.next = pre;
//改变pre位置
pre = head;
//改变head位置
head = next;
}
return pre;
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.last = head;
head.next.next = new Node(3);
head.next.next.last = head.next;
head = reverseDoubleList(head);
System.out.println(head.vaule);
System.out.println(head.next.vaule);
System.out.println(head.next.next.vaule);
}
}
题目三:用单链表实现队列
接收一些数据(为队列),然后按接收的顺序输出
public class LinkedListToQueue {
public static class Node<E> {
E vaule;
Node next;
public Node(E vaule) {
this.vaule = vaule;
}
}
static class MyQueue<V>{
Node<V> head;
private Node<V> tail;
public MyQueue() {
}
public void get(V v){
Node<V> node = new Node<>(v);
if(head != null){
tail.next = node;
}else{
head = node;
}
tail = node;
}
public V peek(){
V ans = head.vaule;
head = head.next;
//防止产生脏数据
if(head == null){
tail = null;
}
return ans;
}
}
public static void main(String[] args) {
MyQueue<Integer> mq = new MyQueue<>();
mq.get(1);
mq.get(2);
mq.get(3);
System.out.println(mq.peek());
System.out.println(mq.peek());
System.out.println(mq.peek());
}
}
脏数据:从目标中取出的数据已经过期、错误或者没有意义,这种数据就叫做脏数据。
题目三:用单链表实现栈
接收一些数据(为栈),然后按接收的倒序输出
public class LinkedListToStack {
static class Node<E> {
E vaule;
Node next;
Node() {
}
Node(E vaule) {
this.vaule = vaule;
}
static class MyStack<V> {
Node<V> head;
MyStack() {
}
void put(V v) {
Node<V> node = new Node<>(v);
node.next = head;
head = node;
}
V peek() {
V ans = head.vaule;
head = head.next;
return ans;
}
}
}
public static void main(String[] args) {
//引用类型的传递(当被指向的对象改变时(属性改变不算),指向对象会代替原位置)
Node<Integer> node = new Node<>(1);
Node<Integer> node2 = new Node<>(2);
Node<Integer> node3 = new Node<>(3);
node = node2;
System.out.println(node.vaule);//2
node2.vaule = 1;
System.out.println(node.vaule);//1
System.out.println(node == node2);//true
node2 = node3;
System.out.println(node == node2);//false
Node.MyStack<String> ms = new Node.MyStack<>();
ms.put("我是");
ms.put("中国人");
System.out.println(ms.peek());
System.out.println(ms.peek());
}
}
题目四:用双链表结构实现双端队列
可以在队列两端加元素,读取元素
public class DoubleLinkedListToDeque {
class Node<V> {
public V vaule;
public Node<V> last;
public Node<V> next;
public Node(V v) {
vaule = v;
last = null;
next = null;
}
}
class MyDeque<V> {
private Node<V> head;
private Node<V> tail;
public MyDeque() {
}
void pushHead(V v) {
Node<V> node = new Node<>(v);
if (head == null) {
tail = node;
} else {
head.last = node;
node.next = head;
}
head = node;
}
void pushTail(V v) {
Node<V> node = new Node<>(v);
if (tail == null) {
head = node;
} else {
tail.next = node;
node.last = tail;
}
tail = node;
}
V pollHead() {
V ans = null;
if (head != null) {
ans = head.vaule;
head = head.next;
if (head != null) {
head.last = null;
} else {
tail = null;
}
}
return ans;
}
V pollTail() {
V ans = null;
if (tail != null) {
ans = tail.vaule;
tail = tail.last;
if (tail != null) {
tail.next = null;
} else {
head = null;
}
}
return ans;
}
}
}
双链表不会自动释放
题目五:K个节点的组内逆序调整(Hard)
给定一个单链表的头节点head,和一个正数k
实现每k个数的内部逆序,如果最后一组不够k个就不调整
public static ListNode reverseKGroup(ListNode head, int k) {
ListNode start = head;
ListNode end = getKGroupEnd(start, k);
if (end == null) {
return head;
}
// 第一组凑齐了!
head = end;
reverse(start, end);
// 上一组的结尾节点
ListNode lastEnd = start;
while (lastEnd.next != null) {
start = lastEnd.next;
end = getKGroupEnd(start, k);
if (end == null) {
return head;
}
reverse(start, end);
lastEnd.next = end;
lastEnd = start;
}
return head;
}
public static ListNode getKGroupEnd(ListNode start, int k) {
while (--k != 0 && start != null) {
start = start.next;
}
return start;
}
public static void reverse(ListNode start, ListNode end) {
end = end.next;
ListNode pre = null;
ListNode cur = start;
ListNode next = null;
while (cur != end) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
start.next = end;
}
单链表,因为JVM释放,所以方法的返回值一定不能是void
题目六:链表中的两数相加
public class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public static int getlength(ListNode node) {
int size = 0;
while (node != null) {
size++;
node = node.next;
}
return size;
}
public static ListNode reverse(ListNode head) {
ListNode next = null;
ListNode pre = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int len1 = getlength(l1);
int len2 = getlength(l2);
l1 = reverse(l1);
l2 = reverse(l2);
ListNode l = len1 > len2 ? l1 : l2;
ListNode s = len1 > len2 ? l2 : l1;
int carry = 0;
int num = l.val + s.val + carry;
l.val = num % 10;
ListNode ans = l;
ListNode last = null;
carry = num / 10;
s = s.next;
last = l;
l = l.next;
while (s != null) {
num = l.val + s.val + carry;
l.val = num % 10;
carry = num / 10;
s = s.next;
last = l;
l = l.next;
}
while (l != null) {
num = l.val + carry;
l.val = num % 10;
carry = num / 10;
last = l;
l = l.next;
}
if (carry != 0) {
last.next = new ListNode(1);
}
return reverse(ans);
}
}
题目七: 合并两个有序链表
public class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null || list2 == null) {
return list1 == null ? list2 : list1;
}
ListNode cur = list1.val > list2.val ? list2 : list1;
ListNode ans = cur;
ListNode head2 = cur == list1 ? list2 : list1;
ListNode head = cur.next;
while (head != null && head2 != null) {
if (head.val > head2.val) {
cur.next = head2;
head2 = head2.next;
} else {
cur.next = head;
head = head.next;
}
cur = cur.next;
}
cur.next = head == null ? head2 : head;
return ans;
}
}
本文主要探讨了单链表和双链表的概念,并通过一系列题目讲解了如何进行链表反转、使用链表实现队列和栈,以及双端队列的构建。此外,还涉及到了K个节点的组内逆序调整和链表中的数学运算问题,如两数相加和有序链表合并。
25万+

被折叠的 条评论
为什么被折叠?



