链表(Java)

部分转自https://www.jianshu.com/p/6782f3d96471

单链表

什么是单链表

链表(Linked list)是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的引用(Pointer)。链表并不像数组那样将数组存储在一个连续的内存地址空间里,所以较之数组来说这是一个优势。

单链表的特点

  • 链表增删元素的时间复杂度为O(1),查找一个元素的时间复杂度为 O(n);
  • 单链表不用像数组那样预先分配存储空间的大小,避免了空间浪费;
  • 单链表不能进行回溯操作,如:只知道链表的头节点的时候无法快读快速链表的倒数第几个节点的值。

单链表的基本操作

获取单链表的长度

对于一个链表的长度我们只能一次去遍历链表的节点,直到找到某个节点的下一个节点为空的时候得到链表的总长度:

public int getLength(Node head){
    if(head == null){
        return 0;
    }
    int len = 0;
    while(head != null){
        len++;
        head = head.next;
    }  
    return len;  
}
查询指定索引的节点值或指定节点值的索引

查询指定索引的节点值:

public int getValueOfIndex(Node head, int index) throws Exception {
    if (index < 0 || index >= getLength(head)) {
        throw new Exception("角标越界!");
    }
    if (head == null) {
        throw new Exception("当前链表为空!");
    }
    Node targetHead = head;
    while (targetHead.next != null && index > 0) {
        targetHead = targetHead.next;
        index--;
    }
    return targetHead.value;
}

查询指定节点值的索引:

public int getNodeIndex(Node head, int value) {
    int index = -1;
    Node targetHead= head;
    while (targetHead!= null) {
        index++;
        if (targetHead.value == value) {
            return index;
        }
        targetHead= targetHead.next;
    }
    return -1;
}
添加一个元素

1、在已有链表头部插入一个节点

public Node addAtHead(Node head, int value){
    Node newHead = new Node(value);
    newHead.next = head;
    return newHead;
}

2、在已有链表的尾部插入一个节点:

public void addAtTail(Node head, int value){
    Node node = new Node(value);
    Node targetHead= head;
    while( targetHead.next != null){
        targetHead= targetHead.next;
    }
    targetHead.next = node;   
}

3、在指定位置添加一个节点

public Node insertElement(Node head, int value, int index) throws Exception {
   //为了方便这里我们假设知道链表的长度
   int length = getLength(head);
   if (index < 0 || index >= length) {
       throw new Exception("角标越界!");
   }
   if (index == 0) {
       return addAtHead(head, value);
   } 
   else if (index == length - 1) {
       addAtTail(head, value);
   }
   else {
       Node pre = head;
       Node cur = head.next;
       while (pre != null && index > 1) {
           pre = pre.next;
           cur = cur.next;
           index--;
       }  //循环结束后 pre 保存的是索引的上一个节点 而 cur 保存的是索引值当前的节点
       Node node = new Node(value);
       pre.next = node;
       node.next = cur;
   }
   return head;
}

在指定位置添加一个节点,首先我们应该找到这个索引所在的节点的前一个,以及该节点,分别记录这两个节点,然后将索引所在节点的前一个节点的 next 指针指向新节点,然后将新节点的 next 指针指向插入节点即可。与其他元素并没有什么关系,所以单链表插入一个节点时间复杂度为 O(1)。

而数组插入元素就不一样了如果将一个元素插入数组的指定索引位置,那么该索引位置以后元素的索引位置(内存地址)都将发生变化,所以一个数组的插入一个元素的时间复杂度为 O(n);所以链表相对于数组插入的效率要高一些,删除同理。

删除一个元素

1、 删除头部节点

public Node deleteHead(Node head) throws Exception {
    if (head == null) {
        throw new Exception("当前链表为空!");
    }
    return head.next;
}

2、 删除尾节点:

public void deleteTail(Node head) throws Exception {
    if (head == null) {
        throw new Exception("当前链表为空!");
    }
    Node targetHead = head;
    while (targetHead.next != null && targetHead.next.next != null) {
        targetHead= targetHead.next;
    }
    targetHead.next = null;
}

3、 删除指定索引的节点:

public Node deleteElement(Node head, int index) throws Exception {
    int size = getLength(head);
    if (index < 0 || index >= size) {
        throw new Exception("角标越界!");
    }
    if (index == 0) {
        return deleteHead(head);
    } 
    else if (index == size - 1) {
        deleteTail(head);
    }
    else {
        Node pre = head;
        while (pre.next != null && index > 1) {
            pre = pre.next;
            index--;
        }
        //循环结束后 pre 保存的是索引的上一个节点 将其指向索引的下一个元素
        if (pre.next != null) {
            pre.next = pre.next.next;
        }
    }
    return head;
}

由单链表的增加删除可以看出,链表的想要对指定索引进行操作(增加,删除),的时候必须获取该索引的前一个元素。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,271评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,533评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,580评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,203评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,204评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,664评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,014评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,991评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,536评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,558评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,678评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,267评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,997评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,429评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,580评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,259评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,744评论 2 366

推荐阅读更多精彩内容