大数据知识体系
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
  • 数据结构与算法概述
  • 线性表

    • 线性表 - 基础概念
    • 线性表 - 顺序表
    • 线性表 - 链表
    • 线性表 - 单链表
      • 概念
      • 单链表实现
        • 抽象数据类型
        • 插入结点
        • 删除结点
        • 查找结点
        • 完整代码
    • 线性表 - 单向循环链表
    • 线性表 - 双向链表
    • 线性表 - 栈
    • 线性表 - 队列
  • 树

    • 树 - 基础概念
    • 树 - 二叉树基础
    • 树 - 二叉树建立
    • 树 - 二叉树遍历
    • 树 - 树的常见操作
    • 树 - 线索二叉树
    • 树 - 哈夫曼树
    • 树 - 二叉排序树
    • 树 - 平衡二叉树(AVL树)
    • 树 - 红黑树
    • 树 - B树
    • 树 - B+树
    • 树 - B*树
  • 图

    • 图 - 基础概念
    • 图 - 存储方式
    • 图 - 图遍历
    • 图 - 最小生成树
    • 图 - 最短路径
  • 其它数据结构

    • 稀疏数组
    • 哈希表
  • 排序算法

    • 冒泡排序
    • 选择排序
    • 插入排序
    • 希尔排序
    • 基数排序
    • 归并排序
    • 快速排序
    • 堆排序
  • 查找算法

    • 顺序查找
    • 二分查找
    • 插值查找
    • 斐波那契查找
  • 其它算法

  • 数据结构与算法
  • 线性表
Will
2022-03-24
目录

线性表 - 单链表

# 概念

如果一个 Node 中只有一个指针域,则被称为单链表。

优点:

  • 插入和删除高效,时间复杂度为 O(1)。
  • 不需要提前分配存储空间,元素个数不受限制。

缺点:

  • 查询较慢,时间复杂度为 O(n)。

# 单链表实现

# 抽象数据类型

class Node {
    // 数据域
    public Object data;
    // 指针域
    public Node next;

    public Node() {}

    public Node(Object obj) {
        data = obj;
    }

    @Override
    public String toString() {
        return data.toString();
    }
}

public class LinkList {
    private Node head;
    private int size;

    public LinkList() {
        head = new Node();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 插入结点

假设要在结点 p 和 p->next 结点之间插入结点 s,则需要两步:

  1. 让 s->next = p->next;
  2. 让 p->next = s。

注意:先后顺序不可调。

插入前:

插入后:

思路:

  1. 声明一个结点 p 指向链表头结点,初始化 j 从 0 开始;
  2. 当 j < i 时,就遍历链表,让 p 的指针向后移动,不断指向下一个结点,j 累加 1;
  3. 在系统中生成一个空结点 s;
  4. 将数据元素 e 赋值给 s-> data;
  5. 然后执行 s->next = p->next、p->next = s;
  6. 链表长度+1;
  7. 返回成功。
    /**
     * 在指定位置插入新结点
     *
     * @param obj
     * @param i
     */
    public boolean insert(Object obj, int i) {
        if (i < 0 || i > size) {
            System.out.println("插入位置不正确");
            return false;
        }

        Node s = new Node(obj);
        Node p = head;

        for (int j = 0; j < i; j++) {
            p = p.next;
        }

        s.next = p.next;
        p.next = s;

        size++;
        return true;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 删除结点

删除的主要逻辑是让 p->next = p->next->next,如果要返回删除的元素(p->next),则需要现将 p->next 保存在临时变量中,然后执行删除逻辑,即 t -> p->next,p->next = p->next->next。

思路:

  1. 声明一个节点 p 指向链表头结点,初始化 j 从 0 开始;
  2. 当 j< i 时,就遍历链表,让 p 的指针向后移动,不断指向下一个结点,j 累加 1;
  3. 若到链表末尾 p->next 为空,则说明第 i 个元素不存在;
  4. 否则查找成功,将欲删除的结点 p-> next 赋给 t;
  5. 执行 p->next = p->next->next;
  6. 将 t 结点的数据 t->data 返回;
  7. 链表长度-1;
  8. 返回。
    /**
     * 删除指定位置的元素
     *
     * @param i
     * @return
     */
    public Node remove(int i) {
        if (i < 0 || i > size - 1) {
            System.out.println("删除位置不正确");
            return null;
        }

        Node p = head;
        for (int j = 0; j < i; j++) {
            p = p.next;
        }

        if (p.next == null) {
            // 没找到
            return null;
        } else {
            // 找到了
            Node t = p.next;
            p.next = p.next.next;
            size--;
            return t;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 查找结点

查找第 i 个元素:

  1. 申明一个结点 p 指向链表头结点,初始化 j 从 0 开始;
  2. 当 j< i 时,让 p 的指针向后移动,不断指向向下一个结点,j 累加 1;
  3. 若到链表末尾 p 为空,则说明第 i 个元素不存在;
  4. 否则查找成功,返回结点 p 的数据。
    /**
     * 查找第i个元素
     *
     * @param i
     * @return
     */
    public Object search(int i) {
        Node p = head;

        // i 有可能为0
        for (int j = 0; j <= i; j++) {
            p = p.next;
        }

        if (p == null) {
            return -1;
        } else {
            return p.data;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 完整代码

package com.sqlboy.lineartable;

public class LinkList {
    private Node head;
    private int size;

    public LinkList() {
        head = new Node();
    }

    /**
     * 创建空链表,只有头结点
     */
    public void createList() {
        head.next = null;
        size = 0;
    }

    /**
     * 整表创建空链表
     *
     * @param n
     */
    public void createList(int n) {
        // 创建一个Node,表示前置结点
        Node preNode = null;

        for (int i = 0; i < n; i++) {
            // 创建一个当前节点
            Node node = new Node();

            if (i == 0) {
                head.next = node;
            } else {
                preNode.next = node;
            }

            preNode = node;
            size++;
        }
    }

    /**
     * 打印链表
     */
    public void show() {
        Node node = head.next;
        for (int i = 0; i < size; i++) {
            System.out.println(node.data);
            node = node.next;
        }
        System.out.println();
    }

    /**
     * 在指定位置插入新结点
     *
     * @param obj
     * @param i
     */
    public boolean insert(Object obj, int i) {
        if (i < 0 || i > size) {
            System.out.println("插入位置不正确");
            return false;
        }

        Node s = new Node(obj);
        Node p = head;

        for (int j = 0; j < i; j++) {
            p = p.next;
        }

        s.next = p.next;
        p.next = s;

        size++;
        return true;
    }

    /**
     * 查找第i个元素
     *
     * @param i
     * @return
     */
    public Object search(int i) {
        Node p = head;

        // i 有可能为0
        for (int j = 0; j <= i; j++) {
            p = p.next;
        }

        if (p == null) {
            return -1;
        } else {
            return p.data;
        }
    }

    /**
     * 删除指定位置的元素
     *
     * @param i
     * @return
     */
    public Node remove(int i) {
        if (i < 0 || i > size - 1) {
            System.out.println("删除位置不正确");
            return null;
        }

        Node p = head;
        for (int j = 0; j < i; j++) {
            p = p.next;
        }

        if (p.next == null) {
            // 没找到
            return null;
        } else {
            // 找到了
            Node t = p.next;
            p.next = p.next.next;
            size--;
            return t;
        }
    }

    public static void main(String[] args) {
        LinkList list = new LinkList();
        list.insert(new Integer(0), 0);
        list.insert(new Integer(1), 1);
        list.insert(new Integer(2), 2);
        list.insert(new Integer(3), 3);

        list.show();

        System.out.println(list.remove(3));
        System.out.println();
        list.show();


//        LinkList list2 = new LinkList();
//        list2.createList(5);
//        list2.show();
    }
}

class Node {
    // 数据域
    public Object data;
    // 指针域
    public Node next;

    public Node() {}

    public Node(Object obj) {
        data = obj;
    }

    @Override
    public String toString() {
        return data.toString();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
上次更新: 2023/11/01, 03:11:44

← 线性表 - 链表 线性表 - 单向循环链表→

Theme by Vdoing | Copyright © 2022-2023 Will 蜀ICP备2022002285号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式