链表
链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段链接在一起。
线性数据结构
与数组一样,链表也是线性数据结构,他们的区别在于存储方式不同。
- 顺序存储结构(数组):快速的存和取,逻辑上相邻,物理上也相邻。
- 链式存储结构(链表):快速的删和改,节点在内存中并不相邻,且相比数组需要更多存储空间。
Tips:链表的遍历时间复杂度为O(n),增删的时间复杂度为O(1)
定义单个节点结构体
public class SinglyListNode { //以单链表为例
int val;
SinglyListNode next;
SinglyListNode(int x) { val = x; }
}
链表的基本操作
链表的增删
设计链表的实现。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。
class MyLinkedList {
Node head; //虚拟头结点
int size;
class Node{ //节点类
int val;
Node next;
Node(){}
Node(int val){
this.val=val;
this.next=null;
}
}
/** Initialize your data structure here. */
public MyLinkedList() {
head=new Node();
size=0;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
public int get(int index) {
Node p=head;
if(index >= size || index < 0)return -1;
for(int i=-1;i<index;i++) //有一个头结点,i从-1开始
{
p=p.next;
}
return p.val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
public void addAtHead(int val) {
addAtIndex(0,val);
}
/** Append a node of value val to the last element of the linked list. */
public void addAtTail(int val) {
addAtIndex(size,val);
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
public void addAtIndex(int index, int val) {
if(index<=size&&index>=0)
{
Node node= new Node(val); //需要插入的节点
if(index==0)
{//插入在头结点
node.next=head.next;
head.next=node;
}
else
{//插入在index位置
Node p=head;
for(int i=-1;i<index-1;i++)
{
p=p.next;
}
node.next=p.next;
p.next=node;
}
}
size++;
}
/** Delete the index-th node in the linked list, if the index is valid. */
public void deleteAtIndex(int index) {
if(index >= 0 && index < size){
if(index == 0){
head.next = head.next.next;
}else{
Node p = head;
int i = -1;
while(i < index - 1){
p = p.next;
i++;
}
p.next = p.next.next;
}
size--;
}
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
反转链表——头插法
解决方案:按原始顺序迭代结点,并将它们逐个移动到列表的头部。
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode prev=head;
ListNode p=prev.next;
while(p!=null)
{
prev.next=p.next; //保存p的后继节点
p.next=head;
head=p;
p=prev.next;
}
return head;
}