数据结构学习笔记(二)---单链表

单链表中结点类型的描述如下:

class LNode {
    Integer data;
    LNode next;
}

1.头插法建立单链表。
从一个空表开始,生成新节点,并将读取到的数据存放到新节点的数据域中,然后将新节点插入到当前链表的表头,即头结点之后,如图所示:

这里写图片描述

算法如下:

public LNode createList1() {
        LNode l = new LNode();
        l.next = null;
        for(int i=0; i<10; i++) {
            LNode tmp = new LNode();
            tmp.data = i;
            tmp.next = l.next;
            l.next = tmp;
        }
        return l;
    }

2.尾插法建立单链表
将新节点插入到当前链表的表尾,为此增加一个尾指针r,使其指向当前链表的表尾,如图:

这里写图片描述

算法如下:

    public LNode createList2() {
        LNode l = new LNode();
        LNode r = l;
        for(int i=0; i<10; i++) {
            LNode tmp = new LNode();
            tmp.data = i;
            r.next = tmp;
            r = tmp;
        }

        r.next = null;

        return l;
    }

3.按序号查找节点值。

在单链表中从第一个节点出发,顺指针next域住个往下搜索,直到找到第i个节点为止,否则返回最后一个节点指针域NULL。

    public LNode getElem(LNode l, int i) {

        if(i < 1) {     //如果要查找的元素的位置比1还小,返回NUll
            return null;
        }

        int j = 1; 
        LNode p = l.next;

        while(null != p && j < i) {     //从第一个节点开始查找,查找第i个节点
            p = p.next;
            j++;
        }
        return p;   //返回第i个节点的指针,如果i大于表长,p=NULL
    }

4.按值查找表节点
从单链表第一个节点开始,由前往后依次比较表中各节点数据域的值,若某节点数据域的值等于给定值e,则返回该节点指针,若整个单链表中没有这样的节点,则返回NULL。

    public LNode locateElem(LNode l, int e) {
        LNode p = l.next;
        while(null != p && e != p.data) {
            p = p.next;
        }
        return p;
    }

5.插入节点操作

插入操作是将值为x的新节点插入到单链表的第i个位置。首先检查插入位置的合理性,然后找到待插入位置的前驱节点,即第i-1个元素,再在其后面插入新的节点。
算法首先调用getElem(LNode l)方法查找第i-1个节点,假设返回的第i-1个节点为p, 然后令新节点s的指针指向p的后继节点,再令节点p的指针域指向新插入的节点s,如图所示:

这里写图片描述

(1) p = getElem(l, i-1);
(2) s.next = p.next;
(3) p.next = s;

本算法主要开销在查找第i-1个元素,时间复杂度为O(n)。

此外,可以采用另一种方式将其转换为后插操作来实现,设带插入节点为s,将s插入到p的前面。我们采用将s插入到p的后面的方式,然后将p.data与s.data交换即可,这样既能满足逻辑关系,又能使得时间复杂度为O(1),思想如下:

s.next = p.next;
p.next = s;
temp = p.data;
p.data = s.data;
s.data = temp;

6.删除节点元素
删除操作是将单链表的第i个节点删除,先检查其删除位置的合法性,然后查找表中第i-1个节点,即被删除节点的前驱节点,再将其删除,如下图所示:

这里写图片描述

假设节点p为找到的被删除节点的前驱节点,为了实现这一操作后的逻辑关系的变化,仅需要修改p的指针域,即将p的指针域next指向q的下一个节点。
代码片段如下:

p = getElem(l, i-1);
q = p.next;
p.next = q.next;
q.next = null;

和插入算法一样,时间主要消耗在查找操作上,时间复杂度为O(n)。

其实,删除节点p的操作可以用删除p的后继节点操作来实现,实质就是将其后继节点的值赋予其自身,然后删除后继节点,使得时间复杂度为O(1)。

q = p.next;
p.data = q.data; //将后继元素的值赋予该元素
p.next = q.next;
q.next = null;
发布了74 篇原创文章 · 获赞 3 · 访问量 6万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章