链表
链表是一种在物理上非连续、非顺序的数据结构,由若干个节点(node)所组成。
单向链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。
链表的第一个节点被称为头节点,最后一个节点被称为尾节点,尾节点的next指针指向空。链表是通过其中的next属性来确定下一个节点,来顺序存储。如图:
下面主要说一下单链表的增删改查的实现方式以及用Java实现单链表的增删改查功能。
查找节点
在查找元素时,链表不像数组那样可以通过下标快速进行定位,只能从头节点开始向后一个一个节点逐一查找。
例如给出一个链表,需要查找从头节点开始的第4个节点。
第一步,将查找的指针定位到头节点。
第二步,逐渐向后移动,直到找到目标节点。
只能按照顺序访问,所以最坏的时间复杂度是找到最后一个情况下,为O(n)。
更新节点
直接把旧数据换成新数据即可。
如图:
插入节点
链表插入节点时分为三种情况。
- 尾部插入
- 头部插入
- 中间插入
尾部插入把最后一个节点的next指针指向新插入的节点。
头部插入:
1、把新节点的next指针指向原先的头节点。
2、把新节点变成链表的头节点。
中间插入:
1、把插入位置的前置节点的next指针指向插入的新节点。
2、将新节点的next指针指向前置节点的next指针原先所指向的节点。
删除元素
链表的删除分为三种情况。
- 尾部删除
- 头部删除
- 中间删除
尾部删除,把倒数第2个节点的next指针指向空即可。
头部删除,把链表的头结点设为原先头节点的next指针即可。
中间删除,同样很简单,把要删除节点的前置节点的next指针,指向要删除的元素的下一个节点即可。
之前用C语言写过一个用单链表实现学生管理系统,这次的话就用Java实现以下简单的增、删、插功能。
//实现单链表的增、删、插 public class LinkList { //头指针 private Node head; //尾指针 private Node last; //链表实际长度 private int size; /** * 链表结点 */ private static class Node{ String data; Node next; Node(String data){ this.data = data; } } /** * 输出链表 */ public void output(){ Node temp = head; while(temp != null){ System.out.println(temp.data); temp = temp.next; } } /** * 链表插入元素 * @param data 插入元素 * @param index 插入位置 */ public void insert(String data , int index)throws Exception{ if(index < 0 || index > size){ throw new IndexOutOfBoundsException("超出链表节点范围"); } Node insertedNode = new Node(data); if(size == 0){ //空链表 head = insertedNode; last = insertedNode; }else if(index == 0){ //插在头部 insertedNode.next = head; head = insertedNode; }else if(size == index){ //插在尾部 last.next = insertedNode; last = insertedNode; }else{ //插在中间 Node prevNode = get(index-1); Node nextNode = prevNode.next; prevNode.next = insertedNode; insertedNode.next = nextNode; } size++; } /** * 链表删除位置 * @param index 删除的位置 */ public Node remove(int index)throws Exception{ if(index < 0 || index >size){ throw new IndexOutOfBoundsException("超出链表范围"); } Node removeNode = null; if(index == 0){ //删除头结点 removeNode = head; head = head.next; }else if(index == size){ //删除尾结点 Node prevNode = get(index-1); removeNode = prevNode.next; prevNode.next = null; last = prevNode; }else{ //删除中间结点 Node prevNode = get(index-1); Node nextNode = prevNode.next.next; removeNode = prevNode.next; prevNode.next = nextNode; } return removeNode; } /** * 链表查找元素 * @param index 查找的位置 */ public Node get(int index)throws Exception{ if(index < 0 || index > size){ throw new IndexOutOfBoundsException("超出链表结点范围"); } Node temp = head; for(int i = 0; i < index; i++){ temp = temp.next; } size--; return temp; } public static void main(String[] args) throws Exception { LinkList ll = new LinkList(); ll.insert("你好", 0); ll.insert("我很好", 1); ll.insert("你呢", 2); ll.insert("我不好", 3); ll.insert("为什么呢", 1); ll.output(); ll.remove(0); ll.output(); } }
关于单链表的操作就讲完了,但只是最简单的链表,还有双向链表和循环链表,操作也不是很难,在下次会说的。