数据结构 第二章 向量(上)

本文深入探讨了向量数据结构的实现原理,包括构造与析构过程,向量的加倍式扩容策略及其分摊成本分析,有序向量的唯一化算法及二分查找的复杂度分析。

(a)接口与实现

//构造函数:
Vector(int c=DEFAULT_CAPACITY, int s = 0, T v=0)
{
_elem = new T[_capacity =c];//_capacity为实际物理容量,_size为当前大小
//复制构造函数,使用指针而并非引用
Vector(T const *A,Rank lo,Rank hi){copy_from(A,lo,hi);}
for(_size=0;_size<s;_elem[_size++]=v)}
//析构函数:
~Vector(){delete [] _elem;}
//copy_from函数的实现:
template <typename T>
void copy_from(T const *A,Rank lo,Rank hi){
_elem = new T[_capacity=2*(lo-hi)];//开辟两倍需要复制长度大小的内存空间
_size=0;
while(lo<hi)
	_elem[_size++] = A[lo++];
}

(b)向量的加倍式扩容

向量的加倍式扩容的分摊成本为 O ( 1 ) O(1) O(1)
在这里插入图片描述
注:图中每次只插入一个元素,连续插入2^m个元素
分摊分析:对数据结构实时连续的足够多次的操作,所需的成本分摊到单次操作

(c )有序向量

有序向量的唯一化

方法:从第i个元素开始,往后查找首个不相等元素第j,将第j个元素移动到i+1位,然后再从第i+1位开始往复,直到j=_size,此时向量长度为i+1,重复元素个数为j-i
在这里插入图片描述

template <tupename T> int Vrctor<T>::uniquify(){
Rank i=0,j=0;
while(++j<_size)
	if(_elem(i)!=_elem[j])//跳过雷同者
		_elem[++i]=_elem[j];
_size=++i;shrunk();//剔除末尾的元素
return j-i
}

有序向量的二分查找

语义约定:有便于有序向量自身的维护:V.insert(1+V.search(e),e)
1)即便新元素查找失败,也应该给出新元素适当的插入位置
2)若允许重复元素,则每一组重复元素也需按照插入次序排序
约定:在有序向量V[lo,hi)中,确定不大于e的最后一个元素,取该元素的后一位作为插入位置
若e过小,则返回lo-1;若e过大,则返回hi-1
在这里插入图片描述

static rank binSearch(T *A,T const& e,Rank lo,Rank hi)
{
while(lo<hi){
	Rank mi=(lo+hi)>>1;
	if (e<A[mi]) hi=mi;
    else if(A[mi]<e) lo=mi+1;
	else return mi;
	}
return -1; 
}

复杂度分析:
先行递归 T ( n ) = T ( n / 2 ) + O ( 1 ) T(n)=T(n/2)+O(1) T(n)=T(n/2)+O(1), O ( 1 ) O(1) O(1)表示每次只需要进行1到2次的常数次比较
递归跟踪:轴总取中点,各实例递归耗时O(1),总递归数量 l o g n logn logn,所以递归深度 O ( l o g n ) O(logn) O(logn)

考察关键码的比较次数,即查找长度(search lenght):
查找成功和失败的两种情况平均查找长度大致为 O ( 1.5 l o g n ) O(1.5logn) O(1.5logn)
在这里插入图片描述
往左的时候只需要一次对比,往右需要两次,因为程序中是先对比左边,若不满足再对比右边的。最底层(d)表示失败的情况

### 数据结构中线性表的应用 #### 线性表的概念及其重要性 线性表是一种常见的数据结构,它由一组具有相同特性的数据元素组成,并且这些元素之间存在一对一的关系。在线性表中,除了第一个最后一个元素外,其他每个元素都有唯一的一个前驱后继[^1]。 #### 线性表的具体应用示例 以下是几个具体的线性表应用场景: 1. **多项式的表示与计算** 多项式可以通过线性表的形式进行存储表达。例如,对于一元 m 次多项式 \( P(x) \),可以用一个线性表 Q 来表示其系数序列。如果需要对两个多项式进行加法运算,也可以通过创建一个新的线性表 R 来保存结果[^2]。 2. **字符串处理** 字符串本质上是一个字符型的线性表,在实际编程过程中经常涉及字符串的拼接、查找以及替换等操作。这些都可以基于线性表的基本操作实现。 3. **学生信息管理系统** 学生的信息(如学号、姓名、成绩等)可以被看作是由多个字段组成的记录集合,这种记录集合通常会以线性表形式管理。比如使用顺序表或者单链表来维护学生的成绩单并支持增删改查功能。 4. **栈队列的基础构建** 虽然栈队列有各自特殊的访问规则,但它们实际上也是特定类型的线性表。因此理解好基础的线性表概念有助于进一步掌握更复杂的抽象数据类型。 #### 实现细节——C++ 中的顺序表操作 下面展示如何利用 C++ 完成一些基本的顺序表操作,包括初始化、插入、删除等功能。 ##### 初始化顺序表 ```cpp #define MAXSIZE 100 // 声明顺序表的最大长度 typedef struct { ElemType* elem; // 线性表的基地址(初始地址) int length; // 顺序表的实际长度 } SqList; // 初始化函数定义 void InitList(SqList& L){ L.elem = new ElemType[MAXSIZE]; L.length = 0; } ``` ##### 删除指定值的所有节点 当需要高效地从顺序表中移除所有等于某个给定值 `x` 的元素时,可采取双指针技术优化性能至 O(n)[^4]: ```cpp bool RemoveAllX(SqList &L, const ElemType x){ if (L.length == 0 || !L.elem) return false; int i=0,j=0; while(i<L.length){ if(L.elem[i]!=x){ L.elem[j++]=L.elem[i++]; } else{ ++i; } } L.length=j; return true; } ``` #### 结论 通过对上述理论知识的学习及实践案例分析可以看出,无论是简单的数组还是动态分配内存空间形成的向量容器都属于广义上的线性表范畴。熟练运用各种针对线性表的操作技巧不仅能够提高程序运行效率还能增强解决问题的能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值