在聊时间复杂度之前先对数据结构有个大概的了解(不重要)
数据结构是一种具有一定逻辑关系,在计算机中应用某种存储结构,并且封装了相应操作的数据元素集合。它包含三方面的内容,逻辑关系、存储关系及操作。
有一个很著名的公式 “程序=数据结构+算法”,就是一套方法,需要的时候拿过来,套用就可以。
-------------------------------------------------------------------------------------------------------------------------------
算法复杂度包括空间复杂度(内存问题)和时间复杂度(代码编写问题)。
空间复杂度:这里不讨论。
时间复杂度:理论上,一个算法运行所需要的时间。实际是得不到准确的值的,因为机器设备,配件不同,时间不同。
例一:
void Func1(int n)
{
count = 0;
for(int i = 0; i < n; ++i)
{
for(int j = 0;j < n; ++j)
{
++count;
}
}
for(int k = 0; k < 2*n; ++k)
{
++count;
}
for(int m = 0; m < 10; ++m)
{
}
}
此刻整个代码的运行次数为:F(n)= n^2+2*n+10,
注:将F(n)变为空间复杂度时,1)整数可以省略掉,2)与n相乘的整数省略
原因:空间复杂度就是当n为任意值时,找出对F(n)最后结果影响最大的项,其中与n相乘的整数可以省略。
则例一的空间复杂度为O(n^2+n)-----n也可以换成m,k,j......
例二:
void Func2(int n,int m)
{
int count = 0;
for(int i = 0; i < n; ++i)
{
++count;
}
for(int j = 0; j < m; ++j)
{
++count;
}
}
F(n)=n+m
当题目说明n与m相似时O(n)=2n=2m=n=m
n>>m:O(n)
m>>n:O(m)
当题目没有说明:O(m+n)
注:当F(n)=常数时,时间复杂度为O(1)
void Func3(char *str) //*为取地址符,相当于C中的&
{
while(*str) //*str在函数外已经定义好了,是一串字符
{
if(*str == "#")
return 'ok';
else
++str; //位置加1
}
}
同样的,也可以计算字符串。
那么来进行一个小练习吧!
当*str = effective ,#=e。时间复杂度为多少----------------------------------------------------O(1)
当*str = effective,#=f。 时间复杂度为多少-----------------------------------------------------O(1)
当*ste给出具体的字符或数,#未给出具体的字符或数时,时间复杂度:O(1)
>>因为*str是具体的,F(n)是有限次的
当*ste未给出具体的字符或数,#未给出具体的字符或数时,时间复杂度:O(n)
>>无法确定次数,但最好结果是1,最坏结果是n(最后一个),取最坏结果为时间复杂度。
void Func4(int *a,int n)
{
for(int end = n; end > 0; --end)
{
int exchange = 0;
for(int i = 0; i < end; ++i)
{
if(a[i-1] > a[i])
{
swap(a[i-1],a[i]);
exchange = 1;
}
}
if(exchang == 1)
break;
}
}
F(n)=(n-1)+(n-2)+(n-3)......+1=n*(n-1)/2=(n^2-n)/2 时间复杂度为n^2-n
//斐波那契序列
void Func5(int n)
{
if(n < 3)
return 1;
return Func4(n-1)+Func4(n-2);
}
面对递归是每次递归的次数相乘,这里需要用到树形图,之后会讲到。
f(n)=2^0+2^1+2^2...2^(n-1)-x, x为一个常数。这里不懂没关系,后面还会讲。
时间复杂度为O(2^n)
总结一下:时间复杂度不是只看代码就能得出来的,要通过代码得到一个思路,在应用数学知识在这个思路的基础上,算出最后结果。
物理位置随机,也就是随机存储,但有一定的逻辑顺序。逻辑顺序的实现依靠指针。有一个结点叫做单链表,两个结点叫做双链表。
由数据域和指针域组成
指向第一个结点的指针,没有数据域。有头结点时指向头结点,没有头结点指向第一个结点
数据域为空,指针域指向第一个节点
链表: 随机存储,顺序存取
顺序表:顺序存储,随机存储
typedef struct Lnode{
ElemType data; //定义数据域
struct Lnode *next; //因为指针指向下一个结点,所以指针类型为steuct Lnode
}Lnode,*LinkList;
头结点一般定义为L,整个链表也称为L;
定义头结点为Lnode *p;
定义其它结点LinkList p;
Status InitList_L(LinkList &L){
L = (LinkList) malloc (sizeof(LNode));
}
(空链表:头指针和头结点存在)
int ListEmpty(LinkList){
if(L->next)
return 0;
else
return 1;
}
Status DestroyList_L(LinkList &L){
Lnode *p;
while(L){
p = L;
L = L->next;
delete p;
}
}
Status ClearList(LinkList &L){
Lnode *p,*q;
p = L->next;
while(p){
q = p->next;
delete p;
p = q;
}
L->next = null;
return ok;
}
清空链表,头结点不动,所以需要q代替L(相对于销毁链表而言)。
int ListLength_L(LInkList L){
LinkList p;
p = L->next;
i = 0;
while(p){
i++;
p = p->next;
}
}
主要是查找
Status GetElem_L(LinkList,int i,ElemType &e){
p = L->next;
j = 1;
while(p && j < i){
p = p->next;
++j;
}
if(!p || j > i)
return error;
e = p->data;
return ok;
}//GetElem_L
先查找,在插入
Status ListInsert_L(LinkList &L,int i,ElemType e){
p = L;j = 0
while(p && j < i-1)
{p = p->next;++j} //查找第i-1个元素
if(!p || j > i-1)
return error; //保证查找到的是第i-1个结点,并且存在
s = new Lnode;
s-> = e;
s->next = p->next;
p->next = s; //将s插入
return ok;
}//ListInsert_L
大家可以尝试一下,删除第i个结点是怎样操作的
void CreateList_H(LinkList &L,int n){
L = new Lnode;
L->next = null;
for(i = n; i > 0; i--)
{
p = new Lnode;
cin>>p->next; //获得新元素,在c中表示为scanf("&d",&p->data)
p->next = L->next; //插入新结点
L->next = p;
}
void CreateList_R(LinkList &L,int n){
L = new Lnode;
L->next = null;
r = L;
for(i = n; i < 0;--i){
p = new Lnode;
cin>>p->data;
p->next = null;
r->next = p;
r = p;
}