向量与列表 | 数据结构

数据结构课程体系:数据逻辑结构设计 + 存储结构实现+ 运算接口实现
逻辑结构的设计来源于算法的设计,后两者的实现实际上是算法的实现

递归的时间复杂度的计算

写时间复杂度的递推式
减治:return sum(n-1)+A[n]
T ( N ) = T ( N − 1 ) + 1 T(N)=T(N-1)+1 T(N)=T(N1)+1
分治:return sum(A, lo, mi) + sum(A, mi+1, hi)
T ( N ) = 2 ∗ T ( N / 2 ) + O ( 1 ) , T ( N ) = O ( N ) T(N)=2*T(N/2)+O(1),T(N)=O(N) T(N)=2T(N/2)+O(1),T(N)=O(N)


向量

线性表中的元素放在连续的存储空间中;可以用一维数组表示
与数组的区别:泛化(支持更多数据类型 可以非基本) ,自带操作接口

自动扩充

size大于capacity时,自动扩充到现在capacity的两倍
相比数组来说,是动态空间管理 实现比较复杂 但是避免了上溢 空间浪费等问题

扩容(分摊时间复杂度 也就是平均每次操作的时间复杂度)时间复杂度分析:
将所有的操作中用于数组扩容的时间累加起来,除以n,只要n足够大,这一事件就是用于扩容处理的分摊时间成本
每次扩容一倍 O ( 2 ) O(2) O(2)
∑ n = i l o g 2 N 2 n N = O ( 2 ) \frac{\sum_{n=i}^{log_2N}2^n}{N}=O(2) Nn=ilog2N2n=O(2)
每次扩充固定容量 O ( N / 2 X ) O(N/2X) O(N/2X)
x ∑ i = 1 i = N / x i N = O ( N ) \frac{x\sum_{i=1}^{i=N/x}i}{N}=O(N) Nxi=1i=N/xi=O(N)

排序

归并排序
T ( N ) = 2 ∗ T ( N 2 ) + O ( N ) T(N)=2*T(\frac{N}{2})+O(N) T(N)=2T(2N)+O(N)
T ( N ) = O ( N l o g ( N ) ) T(N)=O(Nlog(N)) T(N)=O(Nlog(N))
最佳最差平均的时间复杂度都是一样的 不受输入数据的影响

void merge_sort_recursive(int arr[], int reg[], int start, int end) {
    if (start >= end)
        return;
    int len = end - start, mid = (len >> 1) + start;
    //不能整除则向上取整
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    merge_sort_recursive(arr, reg, start1, end1);
    merge_sort_recursive(arr, reg, start2, end2);
    //为避免传参的麻烦直接在此处对有序序列进行排序
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}

需要注意的细节:
start2=mid+1所以两个序列左右都是闭区间;因此在最前面需要判断对于只有一个元素的序列直接返回,不做处理。

唯一化

对于无需序列: O ( N 2 ) O(N^2) O(N2)
对有序向量的唯一化优化:
从前向后遍历,找到与上一个不相同的往前放 O ( N ) O(N) O(N)

查找

直接查找 最好 O ( 1 ) O(1) O(1) 最差 O ( N ) O(N) O(N) , 平均 O ( N ) O(N) O(N)
(插入删除的也相同 )
二分查找 为 O ( l o g ( N ) ) O(log(N)) O(log(N))

// a[],int e
int search(int e,int begin,int end)
{
    int mid=(begin+end)>>1;
    if(e>a[mid])     search(mid+1,end);
    else if(e==a[mid]) return mid;
    else    search(begin ,mid-1);
}

平均查找长度(ASL):平均查找表中的元素个数
A S L = ∑ p i c i ASL=\sum p_i c_i ASL=pici
顺序查找:成功 N − 1 2 \frac{N-1}{2} 2N1;失败 O ( N ) O(N) O(N)
二分查找:成功 ∑ i = 1 i = l o g 2 ( N + 1 ) 2 i − 1 ∗ i N = l o g 2 ( N + 1 ) − 1 \frac{\sum_{i=1}^i=log_2(N+1)2^{i-1}*i}{N}=log_2(N+1)-1 Ni=1i=log2(N+1)2i1i=log2(N+1)1
查找不成功要看叶子节点伸出的外部节点,认为其是等概率的,然后再求平均。

对二分查找的优化:
插值或者斐波那契 都是变化其分点的位置

列表

存储与构建

列表是按照链式结构实现存储,数据元素的物理存储位置可以随便,不一定要线性
顺序存储结构是静态空间的管理策略,通过链式存储结构实现动态空间管理。
但是在访问上需要通过局部邻域的关系去访问,时间复杂度为 O ( n ) O(n) O(n);顺序存储空间可以通过下标去直接访问(随机存取)
(因此链表无法根据秩去直接访问无法采取二分查找)
一个地址需要4个字节去存储

插入/删除节点

插入的时间复杂度为 O ( 1 ) O(1) O(1)(头部), O ( n ) O(n) O(n)(中间及尾部);相比向量来说,尾部的时间复杂度不一样(向量为 O ( 1 ) O(1) O(1))
头节点需要特殊增加,里面不存数据,但是方便运算的实现。尾哨兵的创建也是为了不处理特殊情况
其他节点的加入或者删除都需要知道前驱节点是谁

做题时要看具体要插入删除谁

唯一化

若列表无顺序,则需要类比无序向量唯一化的手段,双重循环, O ( N 2 ) O(N^2) O(N2)
若列表有顺序,依然类比有序向量唯一化的手段,向后遍历,找到不同的再添加。 O ( N ) O(N) O(N)
(具体实现,P指前,Q指P后的节点,若相同则删除Q,然后再比较,不相同再都向后移动)
(每次比较的都是P与P的后继)

归并排序

不需要额外开空间,用begin->previous作为开头一个个去接后续链表就可以实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值