目录

题目15:在长度为 n (n ≥ 1) 的双链表 L 中,删除尾结点的时间复杂度为()。

选项:

正确答案:A

详细解析:

双链表简介:

删除尾结点的操作:

题目分析:

代码示例:

时间复杂度分析:

结论:

题目18:对 n 个不同的排序码进行冒泡排序,在元素无序的情况下比较的次数为()。

选项:

正确答案:A

详细解析:

冒泡排序简介:

比较次数分析:

时间复杂度:

代码示例:

时间复杂度确定方法:

结论:

题目21:给定有 n 个元素向量,建立一个有序单链表的时间复杂度是()。

选项:

正确答案:D

详细解析:

建立有序单链表的过程:

题目分析:

代码示例:

时间复杂度分析:

总结表格:

结论:

题目25:在一个具有 n 个结点的有序单链表中插入一个新结点并仍然有序的时间复杂度是()。

选项:

正确答案:D

详细解析:

有序单链表简介:

插入新结点的操作步骤:

时间复杂度分析:

代码示例:

时间复杂度确定方法:

总结表格:

结论:

题目56:在单链表中删除 p 所指结点的后继结点,该算法的时间复杂度是()。

选项:

正确答案:A

详细解析:

单链表简介:

删除操作简介:

题目具体要求:

操作步骤:

时间复杂度分析:

代码示例:

时间复杂度确定方法:

可能的误区:

结论:

综合总结

时间复杂度总结表

如何确定时间复杂度

代码与时间复杂度结合示例

附加说明:

链表操作时间复杂度对比

冒泡排序时间复杂度详解

总结


题目15:在长度为 n (n ≥ 1) 的双链表 L 中,删除尾结点的时间复杂度为()。

选项:

  • A. O(n)
  • B. O(n log₂n)
  • C. O(n²)
  • D. O(1)

正确答案:A

详细解析:

双链表简介:

双链表(Doubly Linked List)是一种链式数据结构,每个节点包含两个指针:

  • prev:指向前驱节点。
  • next:指向后继节点。
删除尾结点的操作:
  1. 有尾指针的双链表:
    • 时间复杂度:O(1)
    • 原因: 直接通过尾指针访问尾结点,无需遍历链表。
  2. 无尾指针的双链表:
    • 时间复杂度:O(n)
    • 原因: 需要从头遍历整个链表找到尾结点的前驱节点。
题目分析:

题目给出的正确答案是 A. O(n),这意味着假设链表 没有维护尾指针。因此,删除尾结点需要遍历整个链表,时间复杂度为O(n)。

代码示例:

假设我们使用Python来实现双链表的删除尾结点操作。


class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        # self.tail = None  # 假设没有维护尾指针

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node
        new_node.prev = current

    def delete_tail(self):
        if not self.head:
            return
        current = self.head
        while current.next:
            current = current.next
        if current.prev:
            current.prev.next = None
        else:
            self.head = None  # 链表只有一个节点

# 使用示例
dll = DoublyLinkedList()
for i in range(1, 6):
    dll.append(i)
dll.delete_tail()

时间复杂度分析:
  • 遍历链表找到尾结点: O(n)
  • 删除尾结点: O(1)
  • 总时间复杂度: O(n) + O(1) = O(n)
结论:

由于假设双链表没有维护尾指针,删除尾结点需要遍历整个链表,时间复杂度为O(n),因此选项A正确。


题目18:对 n 个不同的排序码进行冒泡排序,在元素无序的情况下比较的次数为()。

选项:

  • A. n(n-1)/2
  • B. n+1
  • C. n
  • D. n−1

正确答案:A

详细解析:

冒泡排序简介:

冒泡排序(Bubble Sort)是一种简单的排序算法,通过重复交换相邻未按顺序排列的元素,将最大的元素“冒泡”到序列的末端。其基本步骤如下:

  1. 从头开始,依次比较相邻的元素。
  2. 如果前一个元素大于后一个元素,则交换它们。
  3. 重复以上过程,直到整个序列有序。
比较次数分析:

在最坏情况下(即元素完全逆序),冒泡排序需要进行最大数量的比较和交换。

  • 第一趟: 比较n-1次,将最大的元素移动到最后。
  • 第二趟: 比较n-2次,将第二大的元素移动到倒数第二个位置。
  • ...
  • 第(n-1)趟: 比较1次,将最小的元素移动到第一个位置。

因此,总的比较次数为: (n−1)+(n−2)+⋯+1=n(n−1)2(n-1) + (n-2) + \cdots + 1 = \frac{n(n-1)}{2}(n−1)+(n−2)+⋯+1=2n(n−1)​

时间复杂度:

冒泡排序的时间复杂度在最坏情况下是 O(n²),因为比较次数与n的平方成正比。

代码示例:

以下是Python中冒泡排序的实现及比较次数的统计。

def bubble_sort(arr):
    n = len(arr)
    comparison_count = 0
    for i in range(n):
        for j in range(0, n-i-1):
            comparison_count += 1
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return comparison_count

# 使用示例
arr = [5, 1, 4, 2, 8]
comparisons = bubble_sort(arr)
print(f"排序后的数组: {arr}")
print(f"比较次数: {comparisons}")

输出:

排序后的数组: [1, 2, 4, 5, 8]
比较次数: 10

对于n=5,比较次数为5*4/2 = 10,符合公式。

时间复杂度确定方法:
  • 外层循环: n次
  • 内层循环: 每次减少一次,共(n-1)次
  • 总比较次数: n(n-1)/2 = O(n²)
结论:

在最坏情况下,冒泡排序需要进行n(n-1)/2次比较,因此选项A正确。


题目21:给定有 n 个元素向量,建立一个有序单链表的时间复杂度是()。

选项:

  • A. O(1)
  • B. O(n²)
  • C. O(n log₂ n)
  • D. O(n)**

正确答案:D

详细解析:

建立有序单链表的过程:
  1. 假设输入向量已经有序:

    • 时间复杂度:O(n)
    • 原因: 直接遍历向量,将元素依次插入链表,无需比较。
  2. 输入向量无序:

    • 时间复杂度:O(n log n)
    • 原因: 需要先对向量进行排序,然后再构建链表。
题目分析:

题目并未明确说明输入向量是否有序。根据给定答案D. O(n),我们假设输入向量已经有序,因此可以在O(n)时间内构建有序单链表。

代码示例:

以下是Python中将有序向量构建为单链表的实现。

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class SortedLinkedList:
    def __init__(self):
        self.head = None

    def build_from_sorted_vector(self, vec):
        for data in vec:
            self.append(data)

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node

    def print_list(self):
        current = self.head
        elems = []
        while current:
            elems.append(current.data)
            current = current.next
        print(" -> ".join(map(str, elems)))

# 使用示例
vec = [1, 2, 3, 4, 5]  # 已排序
sll = SortedLinkedList()
sll.build_from_sorted_vector(vec)
sll.print_list()

输出:

1 -> 2 -> 3 -> 4 -> 5

时间复杂度分析:
  • 构建链表: 遍历向量一次,逐个插入链表末尾,每次插入为O(1)(因为维护了尾指针)。
  • 总时间复杂度: O(n)
总结表格:
情况 操作 时间复杂度
输入向量已排序 逐个插入链表末尾 O(n)
输入向量无序 先排序(O(n log n))+ 构建链表(O(n)) O(n log n)
结论:

根据题目提供的正确答案D. O(n),假设输入向量已经有序,因此建立一个有序单链表的时间复杂度为O(n)


题目25:在一个具有 n 个结点的有序单链表中插入一个新结点并仍然有序的时间复杂度是()。

选项:

  • A. O(n log₂ n)
  • B. O(n²)
  • C. O(1)
  • D. O(n)**

正确答案:D

详细解析:

有序单链表简介:

有序单链表是一种链式数据结构,其中元素按一定顺序(通常是升序或降序)排列。每个节点只有一个指向后继节点的指针。

插入新结点的操作步骤:
  1. 查找插入位置:

    • 从头节点开始,遍历链表,找到第一个比新结点大的节点,插入到其前面。
    • 如果新结点比所有现有节点都大,插入到链表末尾。
  2. 执行插入:

    • 修改前一个节点的next指针,使其指向新结点。
    • 将新结点的next指针指向后一个节点。
时间复杂度分析:
  • 查找插入位置: 最坏情况下需要遍历整个链表,时间复杂度为O(n)。
  • 执行插入: 直接操作指针,时间复杂度为O(1)。
  • 总时间复杂度: O(n) + O(1) = O(n)
代码示例:

以下是Python中在有序单链表中插入新结点的实现。

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class SortedLinkedList:
    def __init__(self):
        self.head = None

    def insert_sorted(self, data):
        new_node = Node(data)
        # 如果链表为空或新节点应插在头部
        if not self.head or data < self.head.data:
            new_node.next = self.head
            self.head = new_node
            return
        # 遍历链表找到插入位置
        current = self.head
        while current.next and current.next.data < data:
            current = current.next
        # 插入新节点
        new_node.next = current.next
        current.next = new_node

    def print_list(self):
        current = self.head
        elems = []
        while current:
            elems.append(current.data)
            current = current.next
        print(" -> ".join(map(str, elems)))

# 使用示例
sll = SortedLinkedList()
for data in [1, 3, 5, 7]:
    sll.insert_sorted(data)
sll.print_list()
sll.insert_sorted(4)
sll.print_list()

1 -> 3 -> 5 -> 7 1 -> 3 -> 4 -> 5 -> 7

时间复杂度确定方法:
  • 查找插入位置: 最坏情况下需要遍历整个链表,O(n)。
  • 指针操作: O(1)。
  • 总时间复杂度: O(n)
总结表格:
操作类型 操作描述 时间复杂度
插入操作 找到插入位置并插入结点 O(n)
结论:

在有序单链表中插入一个新结点并保持有序的时间复杂度为O(n),因此选项D正确。


题目56:在单链表中删除 p 所指结点的后继结点,该算法的时间复杂度是()。

选项:

  • A. O(1)
  • B. O(n)
  • C. O(log₂n)
  • D. O(n²)

正确答案:A

详细解析:

单链表简介:

单链表(Singly Linked List)是一种链式数据结构,每个节点包含一个数据域和一个指向下一个节点的指针(next)。与双链表不同,单链表只支持单向遍历。

删除操作简介:

在单链表中删除一个节点,通常需要访问该节点的前驱节点,以便更新前驱节点的next指针指向被删除节点的后继节点。

题目具体要求:

删除节点p所指结点的后继结点。

操作步骤:
  1. 访问后继结点:

    • 直接通过p的next指针访问p的后继结点,即q = p.next
  2. 更新指针:

    • 将p的next指针指向q.next,即p.next = q.next
  3. 删除结点:

    • 如果需要,可以释放q的内存(在某些编程语言中,如C/C++)。
时间复杂度分析:
  • 访问p和q: 由于已知p的位置,直接通过指针访问q是O(1)时间。
  • 更新指针: 这也是O(1)时间。
  • 删除操作: 释放内存或其他相关操作通常也是O(1)。

因此,整个删除操作的时间复杂度是 O(1)

代码示例:

以下是Python中在单链表中删除p所指结点的后继结点的实现。

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class SinglyLinkedList:
    def __init__(self):
        self.head = None

    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        current = self.head
        while current.next:
            current = current.next
        current.next = new_node

    def delete_successor(self, p):
        if p and p.next:
            q = p.next
            p.next = q.next
            del q  # Python会自动管理内存

    def print_list(self):
        current = self.head
        elems = []
        while current:
            elems.append(current.data)
            current = current.next
        print(" -> ".join(map(str, elems)))

# 使用示例
sll = SinglyLinkedList()
for data in [1, 2, 3, 4, 5]:
    sll.append(data)
sll.print_list()  # 输出: 1 -> 2 -> 3 -> 4 -> 5

# 假设p指向节点3
p = sll.head.next.next  # 节点3
sll.delete_successor(p)
sll.print_list()  # 输出: 1 -> 2 -> 3 -> 5
时间复杂度确定方法:
  • 访问结点p及其后继结点q: O(1)
  • 更新指针和删除操作: O(1)
  • 总时间复杂度: O(1)
可能的误区:

有些人可能认为需要遍历链表才能找到p的前驱节点,从而导致时间复杂度为O(n)。然而,在本题中,p的位置是已知的,无需遍历链表,因此操作是常数时间的。

结论:

在单链表中删除p所指结点的后继结点的时间复杂度是O(1),因此选项A正确。


综合总结

为了更清晰地理解各个操作的时间复杂度,我们将以下列表格进行总结,并附上相应的代码示例。

时间复杂度总结表

题号 操作描述 时间复杂度 说明 代码示例
15 删除双链表的尾结点(假设无尾指针) O(n) 需要遍历链表找到尾结点的前驱节点 见题目15代码
18 冒泡排序在元素完全无序情况下的比较次数 O(n²) 冒泡排序在最坏情况下需要进行n(n-1)/2次比较 见题目18代码
21 建立一个有序单链表(假设输入向量已排序) O(n) 逐个插入元素到链表末尾,时间与元素数量线性相关 见题目21代码
25 在有序单链表中插入一个新结点并保持有序 O(n) 需要遍历链表找到插入位置,最坏情况下遍历整个链表 见题目25代码
56 删除单链表中节点p的后继结点 O(1) 已知p的位置,直接通过指针操作删除后继结点,无需遍历链表 见题目56代码

如何确定时间复杂度

  1. 分析操作步骤:

    • 分解操作步骤,确定每一步的时间复杂度。
    • 考虑最坏情况下的时间复杂度。
  2. 识别循环和递归:

    • 循环次数直接影响时间复杂度。
    • 嵌套循环导致时间复杂度的乘法增加。
  3. 利用已知的算法复杂度:

    • 如排序算法、搜索算法等的已知时间复杂度。
  4. 常数时间操作:

    • 指针操作、赋值等通常为O(1)时间。
  5. 结合数据结构特性:

    • 链表的遍历、插入、删除操作的时间复杂度取决于是否有辅助指针(如尾指针)或额外信息。

代码与时间复杂度结合示例

题目25为例,我们在有序单链表中插入一个新结点:


python

复制代码

def insert_sorted(self, data): new_node = Node(data) if not self.head or data < self.head.data: new_node.next = self.head self.head = new_node return current = self.head while current.next and current.next.data < data: current = current.next new_node.next = current.next current.next = new_node

  • if 语句: 最好情况下(新结点插入头部),时间复杂度为O(1)。
  • while 循环: 最坏情况下需要遍历整个链表,时间复杂度为O(n)。
  • 指针操作: O(1)。

因此,总时间复杂度为 O(n)


附加说明:

链表操作时间复杂度对比

操作类型 单链表(Singly Linked List) 双链表(Doubly Linked List)
访问头结点 O(1) O(1)
访问尾结点 O(n)(无尾指针)
O(1)(有尾指针)
O(1)
插入头结点 O(1) O(1)
插入尾结点 O(n)(无尾指针)
O(1)(有尾指针)
O(1)
删除头结点 O(1) O(1)
删除尾结点 O(n) O(1)
插入任意位置 O(n) O(n)
删除任意位置 O(n) O(n)

冒泡排序时间复杂度详解

情况 时间复杂度 比较次数 交换次数
最好情况 O(n) O(n)(已经有序) O(1)(无需交换)
平均情况 O(n²) O(n²) O(n²)
最坏情况 O(n²) n(n-1)/2 = O(n²) n(n-1)/2 = O(n²)

注意: 冒泡排序在元素已经有序的情况下可以优化为O(n)时间复杂度,但在题目18中明确提到“元素无序”,因此比较次数为n(n-1)/2次。


总结

通过上述详细解析、代码示例以及总结表格,我们可以清晰地理解每个操作的时间复杂度及其原因。以下是关键点的回顾:

  1. 链表操作的时间复杂度:

    • 单链表在访问尾结点时,如果没有尾指针,需要O(n)时间。
    • 双链表若维护了尾指针,删除尾结点可以在O(1)时间内完成。
  2. 排序算法的时间复杂度:

    • 冒泡排序在最坏情况下的比较次数为O(n²)。
  3. 构建有序链表的时间复杂度:

    • 如果输入数据已经有序,建立有序单链表可以在O(n)时间内完成。
    • 否则,需要先排序,时间复杂度为O(n log n)。
  4. 插入操作的时间复杂度:

    • 在有序单链表中插入新结点的时间复杂度为O(n),因为需要遍历找到插入位置。
  5. 删除操作的时间复杂度:

    • 在单链表中删除已知位置的后继结点可以在O(1)时间内完成。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐