时间复杂度
时间复杂度是语句执行的次数,而不是实际时间。
时间复杂度针对执行的次数与问题的规模之间的关系来看的。
凡是处理时间复杂度,一定要注意一点:那就是代码体与循环结束条件之间的关系。
第一关 链表基础
单链表
概念
结点相连,每个结点包含元素的值和指向下一个结点的next指针。最后一个结点的next指向null。一个结点只能有一个后继,但不代表一个结点只能有一个被指向。
做题的时候要注意比较的是值还是结点,有时可能两个结点的值相等,但并不是同一个结点。
-
头结点:第一个结点,可以通过它访问整个链表
-
虚拟结点:为了方便我们处理首部结点。*注意:如果要获得head结点,或者从方法(函数)里返回的时候,则应使用
dummyNode.next
创建列表
public class ListNode { public int val; public ListNode next; ListNode(int x) { val = x; next = null; } } ListNode listnode = new ListNode(1);
遍历链表
”狗熊掰棒子“ 注意别忘记标记表头的指针。
public static int getListLength(Node head){ int len=0; Node cur = head; //标记一下 while(cur!=null){ len++; node = node.next; } return len; }
链表插入
在表头插入
-
创建新节点
-
新结点.next = head
-
head = 新节点 (head要重新指向表头!!!不管用head更简单,因为head变了之后,后续操作不好实现)
在链表中间插入
-
在要删除的结点前一个位置停下,
cur.next
来判断//while循环,下标从1开始的链表 Node pNode = head; int count =1; while(count < position - 1){ pNode = pNode.next; count++; }
-
创建新结点
-
新结点.next = pNode.next
-
pNode.next = 新结点
在表尾插入
简单。尾结点.next = 新结点。
链表删除
在表头删除
简单。把head往后移动一位。
在表中删除
找preNode
,preNode.next = preNode.next.next
。
删除尾结点
找preNode
,将preNode.next == null
。
MyBasicLinkList
-
实现:
-
创建链表2 3 4 6
-
插入5,保持升序 (插入1 插入7)
-
删除1 4 6
-
-
问题:
-
升序插入7,边界问题怎么搞?(已解决)
-
一次次插入好麻烦,一次次删除好麻烦,能否优化?
-
public class MyBasicLinkList {
//创建结点
public static class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
this.next = null;
}
}
//main函数,创建2 3 4 6 插入1,保持升序 删除1 4 6
public static void main(String[] args) {
//创建2 3 4 6
Node head = new Node(2);
System.out.print("链表现在为:");
Node node = new Node(3);
InsertNode(head,node,2);
node = new Node(4);
InsertNode(head,node,3);
node = new Node(6);
InsertNode(head,node,4);
MyBasicLinkList.printLink(head);
System.out.println(" ");
//插入1保持升序
node = new Node(1);
head = SpecialInsertNode(head,node); //记得重新定义head!!!
System.out.print("链表现在为:");
MyBasicLinkList.printLink(head);
//删除1 4 6
head = deleteNode(head,1);
// head = deleteNode(head,4);
// head = deleteNode(head,5); 脑子糊涂了,删除之后position也会变,佛了,好麻烦
System.out.print("链表现在为:");
MyBasicLinkList.printLink(head);
head = deleteNode(head,3);
System.out.print("链表现在为:");
MyBasicLinkList.printLink(head);
head = deleteNode(head,3);
System.out.print("链表现在为:");
MyBasicLinkList.printLink(head);
}
//输出链表
public static void printLink(Node head){
Node cur = head;
while(cur!=null){
System.out.print(cur.val+" ");
cur = cur.next;
}
}
//获取链表长度
public static int getLength(Node head){
int len=0;
Node node = head;
while(node!=null){
node = node.next;
len++;
}
return len;
}
//插入结点
public static Node InsertNode(Node head, Node nodeInsert, int position){
//判断是否为空链表
if(head==null){
return nodeInsert;
}
//判断是否数组越界
int size = getLength(head);
if(position>size+1||position<0){
System.out.println("数组越界");
return head;
}
//在开头插入
if(position == 1){
nodeInsert.next = head;
head = nodeInsert;
return head;
}
//在中间插入,包括在尾部插入
//找preNode
Node preNode = head;
int count =1;
while(count < position - 1){
preNode = preNode.next;
count++;
}
nodeInsert.next = preNode.next;
preNode.next = nodeInsert;
return head;
}
//升序插入
public static Node SpecialInsertNode(Node head, Node nodeInsert){
//处理head
if(head == null){
return nodeInsert;
}
if(head.val > nodeInsert.val){
nodeInsert.next = head;
head = nodeInsert;
return head;
}
//找preNode下标
Node cur = head;
while(cur.next.val< nodeInsert.val){
cur = cur.next;
if(cur.next == null){ //处理插入到最后的情况
cur.next = nodeInsert;
return head;
}
}
nodeInsert.next = cur.next;
cur.next = nodeInsert;
return head;
}
//删除结点
public static Node deleteNode(Node head,int position){
if(head==null){
return null;
}
int size=getLength(head);
if(position>size||position<1){ //size 不是size+1 因为可删除的结点下标范围是[1,size] size+1越界了,删个寂寞
System.out.println("数组越界");
return head;
}
if(position==1){
head = head.next;
return head;
} else {
Node cur = head;
int count = 1;
while (count < position - 1) {
cur = cur.next;
count++;
}
cur.next = cur.next.next;
}
return head;
}
}