编程导航算法通关村第1关|青铜教程学习
1 构造链表定义
链表是一种物理单元上非连续、非顺序,但逻辑存储结构上连续的一种数据结构。
链表结点:由值和后继结点地址组成独立单元
头结点:链表的第一个元素,获得头结点就可以遍历整个链表
虚拟结点:dummyNode.next = next,方便处理头结点问题
//链表的后继结点是唯一的,前驱结点可以不唯一
public class ListNode {
public int val; //该结点值
public ListNode next; //后继结点的地址
public ListNode(int x) {
val = x;
next = null;
}
public static void main(String[] args) {
ListNode listnode=new ListNode(1);
}
}
2 根据指定数组初始化链表
public class BasicLink {
public static void main(String[] args) {
Integer[] a = {1, 2, 3, 4, 5, 6};
Node<Integer> head = initLinkedList(a);
String[] strings = {"小红","小敏","小王","小孙"};
Node<String> head1 = initLinkedList(strings);
System.out.println(head);
System.out.println(head1);
}
/**
* val:存放当前结点的值
* next:存放后继结点的地址
* Node(int x):构造器,初始化结点
*/
static class Node<T> {
public T val;
public Node<T> next;
public Node(T x){
val = x;
next = null;
}
}
/**
* 根据指定数组初始化链表
* @param arr:数组
* @return 链表头结点的地址
*/
private static <T> Node<T> initLinkedList(T[] arr){
Node<T> head = null;
Node<T> cur = null;
for(int i = 0; i < arr.length; i++){
if(i == 0){
head = new Node<>(arr[0]);
cur = head;
}else {
Node<T> newNode = new Node<>(arr[i]);
cur.next = newNode;
cur = newNode;
}
}
return head;
}
3 链表增加与删除结点
public class BasicLinkList {
static class Node {
public int val;
public Node next;
public Node (int val){
this.val = val;
this.next = null;
}
}
public static void main(String[] args) {
// 头部添加节点1
Node head = new Node(1);
System.out.println("头部添加节点1:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 尾部添加节点2
Node node = new Node(2);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("尾部添加节点2:" + BasicLinkList.toString(head));
System.out.println("链表长度为:" + getLength(head));
// 中间添加节点3
node = new Node(3);
head = BasicLinkList.insertNode(head, node, 2);
System.out.println("中间添加节点3:" + BasicLinkList.toString(head));
// 删除中间节点2
head = BasicLinkList.deleteNode(head, 2);
System.out.println("删除中间节点3:" + BasicLinkList.toString(head));
// 删除头部节点1
head = BasicLinkList.deleteNode(head, 1);
System.out.println("删除头部节点1:" + BasicLinkList.toString(head));
}
/**
* 遍历链表,获取链表长度
* @param head
* @return
*/
public static int getLength(Node head){
int length = 0;
Node cur = head;
while (cur!=null){
//当前结点不为空,长度+1
length++;
cur = cur.next;
}
return length;
}
/**
* 根据position插入结点:
* 1:表头插入
* 2:其他位置插入(中间位置插入和尾部插入一样都需要遍历位置之前的链表)
* @param head:链表头结点
* @param newNode:待插入结点
* @param position:待插入位置
* @return 链表头结点
*/
public static Node insertNode(Node head, Node newNode, int position){
//避免空指针异常
if(head == null){
return newNode;
}
int size = getLength(head);
//插入位置校验 合法插入:1~n+1
if(position > size+1 || position < 1){
System.out.println("IllegalPositionError!");
return head;
}
//1.表头插入
if(position == 1){
newNode.next = head;
head = newNode;
return head;
}
//2.其他位置插入,需要获取要插入位置前1位的Node
int count = 1;
Node cur = head;
while (count < position - 1){//count = position-1时循环终止
count++;
cur = cur.next;
}
newNode.next = cur.next;
cur.next = newNode;
return head;
}
/**
* 链表删除结点
* @param head
* @param position
* @return
*/
public static Node deleteNode(Node head,int position){
if(head == null){
return null;
}
int size = getLength(head);
//删除位置校验,合法位置:1~n
if(position < 1 || position > size){
System.out.println("IllegalPositionError!");
return head;
}
//1.头结点删除
if(position == 1){
//原先的head因为没有任何引用,被JVM的垃圾回收机制销毁,所以可以不写head = null
return head.next;
}
int count = 1;
Node cur = head;
while (count < position - 1){
cur = cur.next;
count++;
}
cur.next = cur.next.next;//中间位置和尾部位置一样
return head;
}
public static String toString(Node head){
StringBuilder builder = new StringBuilder();
Node cur = head;
while (cur!=null){
builder.append(cur.val);
builder.append("\t");
cur = cur.next;
}
return builder.toString();
}
}
4 双向链表
public class DoubleLinkedList {
static class Node{
final int val;
Node pre; //前驱结点
Node next; //后继结点
Node(int val){
this.val = val;
pre = null;
next = null;
}
}
public static void main(String args[]){
// 头部添加节点1
Node head = new Node(1);
System.out.println("头部添加节点1:" + toString(head));
System.out.println("链表长度为:" + getLength(head));
// 尾部添加节点2
Node node = new Node(2);
head = insertNode(head, node, 2);
System.out.println("尾部添加节点2:" + toString(head));
System.out.println("链表长度为:" + getLength(head));
// 中间添加节点3
node = new Node(3);
head = insertNode(head, node, 2);
System.out.println("中间添加节点3:" + toString(head));
// 删除中间节点2
head = deleteNode(head, 2);
System.out.println("删除中间节点3:" + toString(head));
// 删除头部节点1
head = deleteNode(head, 1);
System.out.println("删除头部节点1:" + toString(head));
}
/**
* 获取双向链表长度
* @param head
* @return
*/
public static int getLength(Node head){
int length = 0;
Node cur = head;
while (cur!=null){
cur = cur.next;
length++;
}
return length;
}
/**
* 双向链表增加结点
* @param head
* @param newNode
* @param position
* @return
*/
public static Node insertNode(Node head, Node newNode, int position){
if (head == null){
return newNode;
}
int size = getLength(head);
//假如位置从1开始,合法位置为1~n+1
if(position < 1 || position > size+1){
System.out.println("IllegalPositionError!");
return head;
}
//1.表头插入
if(position == 1){
newNode.next = head;
head.pre = newNode;
return newNode;
}
//2.非表头插入
int count = 1;
Node cur = head;
while (count < position-1){
cur = cur.next;
count++;
}
//其他位置插入
if (position != size + 1){
newNode.next = cur.next;
cur.next.pre = newNode;
}
cur.next = newNode;
newNode.pre = cur;
return head;
}
/**
* 双向链表删除结点
* @param head
* @param position
* @return
*/
public static Node deleteNode(Node head, int position){
if(head == null){
return null;
}
int size = getLength(head);
//假如位置从1开始,合法位置为1~n
if(position < 1 || position > size){
System.out.println("IllegalPositionError!");
return head;
}
//表头删除,原head将不可达,被回收
if(position == 1){
head = head.next;
head.pre = null;
return head;
}
int count = 1;
Node cur = head;
while (count < position - 1){
cur = cur.next;
count ++;
}
if(position != size){
cur.next.next.pre = cur.next.pre;
}
cur.next = cur.next.next;
return head;
}
public static String toString(Node head){
StringBuilder builder = new StringBuilder();
Node cur = head;
while (cur!=null){
builder.append(cur.val);
builder.append("\t");
cur = cur.next;
}
return builder.toString();
}
}