链表的特点
所谓链表,链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:查询相对于数组困难,增加和删除容易。
链表声明
public class ListNode { int val; ListNode next; public ListNode(int val) { this.val = val; this.next = null; } }
链表的添加
public void insertList(ListNode head, int val) { ListNode tempNode = new ListNode(val); if (head == null) { head = tempNode; }else { ListNode p = head; while (p.next != null) { p = p.next; } p.next = tempNode; } }
链表的删除
public void deleteListNode(ListNode head, int val) { if (head ==null) return;//为了鲁棒性 if (head.val == val) {//头节点为要删除节点 head = head.next; } else { ListNode p = head; //删除节点需要知道前一个节点,所以判断p.next.val是不是和目标相等 while (p.next !=null && p.next.val != val) { p = p.next; } if (p.next !=null) { p.next = p.next.next;//删除节点 } } }
从尾到头打印链表
方法1:使用栈结构
public void printList1(ListNode head) { if (head == null) return; Stack<ListNode> stack = new Stack<ListNode>(); ListNode p = head; while (p != null) { stack.push(p); p = p.next; } while (!stack.isEmpty()) { p = stack.pop(); System.out.print(p.val+" "); } }
方法2:递归
public void printList2 (ListNode head) { if (head != null) { if (head.next != null) { printList2(head.next); } System.out.print(head.val+" "); } }
反转单链表
public ListNode reverseList (ListNode head) { ListNode pre = null; ListNode next; while (head != null) { next = head.next; head.next = pre; pre = head; head = next; } return pre; }
反转双链表
public class DoubleNode { public int val; public DoubleNode pre; public DoubleNode next; public DoubleNode (int val){ this.val=val; } } public Node reverseList(Node head){ DoubleNode pre=null; DoubleNode next=null; while(head!=null){ //反转第一个节点 next=head.next;//记录下一个节点 head.next=pre;//反转当前节点:next指针指向上一个节点 head.pre=next;//反转当前节点:pre指针指向下一个节点 pre=head;//记录当前节点为下一个节点的pre head=next;//移动到下一个节点 } return pre;//返回新头节点 }