目录
算法的时间复杂度
1. 在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。
2. 几个规则:
加法法则:只保留更高阶的项。(常<对<幂<指<阶)
顺序执行的代码只会影响常数项,可忽略
如有多层嵌套循环,只需关注最深层
在计算算法时间复杂度时,可以忽略所有低次幂项和最高次幂的系数,可以简化算法分析
常数阶:
无论代码执行了多少行,只要是没有循环等复杂结构,那代码的时间复杂度就是O(1)
{x++; s=0}
线性阶:
for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,这类代码都用O(n)来表示它的时间复杂度
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
对数阶:
for (i = 1; i <= n; i = i * 2)
{
x++;
s = 0;
}
设循环体内两条基本语句的频度位f(n),则算法时间复杂度为T(n)=O(log2n)
平方阶:
for(x=1; i<=n; x++)
{
for(i=1; i<=n; i++)
{
j = i;
j++;
}
}
两层嵌套,时间复杂度为O(n**2)
空间复杂度
一个算法的空间复杂度为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,用 S(n) 来定义。
O(1):
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
for (i = 0; i < n / 2; i++)
{
t = a[i];
a[i] = a[n - i - 1];
a[n - i - 1] = t;
}
O(n):
for (i = 0; i < n; i++)
b[i] = a[n - i - 1];
for (i=0;i<n;i++)
a[i]=b[i]
算法原地工作:
算法所需内存空间为常量
线性表
线性表:由n个数据特性相同的数据元素构成的有限序列。
线性表中元素的个数为线性表的长度,n=0时为空表。
线性表的特征
1. 地址连续 2. 依次存放 3. 随机存取 4. 类型相同
(顺序表)基本操作的实现
顺序表的初始化
1. 为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。
2. 将表的当前长度设为0
Status InitList_Sq(SqList &L) {
//构造一个空的顺序表L
L.elem = new Book[MAXSIZE]; //为顺序表分配一个大小为MAXSIZE的数组空间
if (!L.elem)
exit(OVERFLOW); //存储分配失败退出
L.length = 0; //空表长度为0
return OK;
}
取值
取值操作时根据指定的位置序号i, 获取顺序表中第i个数据元素的值。可直接通过数组下标定位得到。
Status GetElem(SqList L, int i, Book &e) {
if (i < 1 || i > L.length)
return ERROR; //判断i值是否合理,若不合理,返回ERROR
e = L.elem[i - 1]; //elem[i-1]单元存储第i个数据元素
return OK;
}
查找
查找操作是根据指定的元素值e,查找顺序表中第i个值与e相等的元素。若查找失败,返回0。
int LocateElem_Sq(SqList L, double e) {
//顺序表的查找
for (int i = 0; i < L.length; i++)
if (L.elem[i].price == e)
return i + 1;//查找成功,返回序号i+1
return 0;//查找失败,返回0
}
插入
插入:在表的第i个位置插入一个新的数据元素e,使长度为n的线性表变成长度为n+1的线性表。
步骤
1. 判断插入位置i是否合法(1<=i<=n+1)
2. 判断顺序表的存储空间是否已满,若满返回ERROR
3. 将第n个至第i个位置的元素依次向后移动一个位置
4. 将插入元素e放入第i个位置
5. 表长加一
Status ListInsert_Sq(SqList &L, int i, Book e) {
//i值的合法范围是1<=i<=L.length+1
if ((i < 1) || (i > L.length + 1))
return ERROR; //i值不合法
if (L.length == MAXSIZE)
return ERROR; //当前存储空间已满
for (int j = L.length - 1; j >= i - 1; j--)
L.elem[j + 1] = L.elem[j]; //插入位置及之后的元素后移
L.elem[i - 1] = e; //将新元素e放入第i个位置
++L.length; //表长增1
return OK;
}
插在第i个结点之前:移动n-i+1次
假设在表的任何位置上插入元素的概率相等,则:
p(i)=1/(n+1)
顺序表插入算法平均时间复杂度为O(n)
删除
步骤:
1. 判断删除位置i是否合法
2. 将第i+1个至第n个元素依次向前移动一个位置
3. 表长减1
Status ListDelete_Sq(SqList &L, int i) {
//i值的合法范围是1<=i<=L.length
if ((i < 1) || (i > L.length))
return ERROR; //i值不合法
for (int j = i; j <= L.length; j++)
L.elem[j - 1] = L.elem[j]; //被删除元素之后的元素前移
--L.length; //表长减1
return OK;
}
假设在表上任何位置上删除元素都是等概率的,则:
p(i)=1/n
顺序表删除算法的平均时间复杂度为O(n)