数据结构(C语言第2版)----时间复杂度和单链表

时间:2023-03-09 06:59:02
数据结构(C语言第2版)----时间复杂度和单链表

马上要到校招了,复习下相关的基础知识。

时间复杂度是什么?

官方解释:

算法的执行时间需要依据算法所编制的程序在计算机上于运行时所消耗的时间来度量。在算法中可以使用基本的语句的执行次数作为算法的时间复杂单位,可以认为一个特定算法时间性能只依赖于问题的规模(n),或者说它是一个特定算法时间性能只依赖于问题n的一个函数f(n),当问题规模n趋近于无穷大时的时间量级就称为算法的渐近时间复杂性,简称时间复杂度。

其实说白了就是看这个程序可以执行多少步,看它是否有循环,最后在把值估计计算下就是时间复杂度了,

先看一个简单的类子;

#include "stdio.h"
int main(){ int i,s=0;
for(i=0;i<=n;i++){
s=s+i;
}
printf("%d\n",s);
return 0;
}

这只是一个for循环而已,那么它的时间复杂度是多少呢;可以将每一步的执行步骤写出来,都加起来,计算出其总的时间复杂度。这个时间复杂度是O(n);也就是线性表示。

看下面的这个表。

名称 时间复杂度T(n) 说明
常量阶 O(1) 于问题规模无关的算法
线性阶 O(n) 相关的单循环
平方阶 O(n*n) 二重循环
对数阶 O(log2^n) 折半查找算法
复合阶 O(nlog2^n) 堆排序算法

一些常见的算法

  • 起泡排序算法(冒泡法)

思路:就是一列数据,拿着第一个数据开始往后面比较,若大于则交换,否则不交换,这样就把其值按照从小到大或者从大到小的顺序来排序。这里需要一个临时变量保存值。

#include "stdio.h"
int main(){
int a[8]={1,3,1,2,34,4,5,6};
int i,j,temp=1; //temp作为临时变量
for(i=1;i<8;i++)
for(j=1;j<=8-i;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
for(i=1;i<8;i++){
printf("%d,",a[i]);
}
printf("你好世界\n");

重点是内层循环的比较,也就是那里面的每一次交换值。时间复杂度为T(n)=O(n^2);

名词解释

数据元素是描述数据的基本单位;数据项是描述数据的最小单元;数据对象是数据的一个子集,数据结构是由数据和结构组成,也就是数据元素及数据元素之间关系的集合。相互之间有一种或多种特定关系的数据元素的集合。

逻辑结构:是以抽象的数学模型来描述数据结构中数据元素之间的逻辑关系,使用二元组来表示;

物理结构:叫做存储结构,是数据结构在计算机内的存储表示,也是内存映像;

在PC内部主要以顺序存储和链式存储来表示数据元素在逻辑上的相邻关系。链式存储结构的特点是逻辑上相邻接的数据元素在存储地址上不一定相邻接,数据元素逻辑上的相邻关系是通过指针来描述的,常用它来描述树状结构和图状结构在计算机内部的存储。

数据类型就是一个值的集合和定义在这个值集上的一组操作的总称。

思维导图:第一次使用感觉还不错。就感觉流程图一样但是给人感觉不一样,很直观,没有什么冗余在里面。

数据结构(C语言第2版)----时间复杂度和单链表

数据结构(C语言第2版)----时间复杂度和单链表

了解线性表

线性表是n个数据元素a1,a2,…an组成的有限序列,记为L=(a1,a2…an);若n=0,则表示空表;同一个数据线性表中的数据元素必须具有相同的属性,即属于同一数据对象。

顺序表就是把线性表中的数据元素按其逻辑顺序依次存储在物理地址上也相邻的存储单元中,这种存储结构称为顺序结构存储,用顺序存储结构表示顺序表;顺序表的存储结构是一种随机存取的存储结构。

/*
01---顺序表的存储
*/ //表的定义
typedef int ElemType;
#define INITSIZE 100; //初始分配量
//定义了结构体
typedef struct{
ElemType *data; //数据域
int length; //长度
int listsize; //当前的存储容量
} sqlist; //为顺序表的类型名 //初始化操作
void initlist(sqlist *L){
L->data=(ElemType *)malloc(sizeof(ElemType)*INITSIZE); //动态申请存储空间
L->length=0;
L->listsize=INITSIZE;
}
//求表长操作
int getlen(sqlist *L){
return(L->length);
}
//取出数据元素
int getelem(sqlist *L,int i,ElemType *e){
if(i<1||i>L->length)return 0;
*e=L->data[i-1]; //相当与数组一样,下标差一位。
return 1;
}
//元素定位操作
int locate(sqlist *L,ElemType x){
int i=0;
while(i<L->length){
if(L->data[i]==x)
return i+1;
else
i++;
}
return 0;
}
//插入操作
int insert(sqlist *L,int i,ElemType x){
int j;
if(i<1||i>L->length+1)return 0;
if(L->length==L->listsize){
L->data=(ElemType *)realloc(L->data,(L->listsize+1)*sizeof(ElemType));
L->listsize++;
}
for(j=L->length-1;j>=i-1;j--){
L->data[j+1]=L->data[j]; //将所有的元素后移一位。
L->data[i-1]=x; //将元素插入i位置处。
L->length++; //长度加1;
return 1;
}
}
//删除元素
int delete(sqlist *L,int i,ElemType *e){
int j;
if(i<1||i>L->length)return 0;
*e=L->data[i-1];
for(j=i;j<L->length;j++){
L->data[j-1]=L->data[j];
L->length--;
}
}
//输出操作
void list(sqlist *L){
int i;
for(i=0;i<L->length;i++)
printf("%5d",L->data[i]);
printf("\n");
}

了解链表

顺序表在插入删除时需要移动大量的数据,这样导致内存消耗大,时间长,至此发明了链表来处理这种情况,使用链表可以指定在那里插入数据,不会移动所有的元素.只是指针的变化.当然这里也有缺点,只能进行顺序的存取,不行随机存取.

对于链表我们在内存中可以不按照顺序存储,只需要就将其指针对应起来,通过指针就可以找到所有的存储地点 。

  • 单链表:只有两个区域,数据区和指针区,且有一个 头指针,最后一个数据与为NULL,所有的结点通过指针连接起来而组成链表。由于每个结点只包含一个指针域,所以称为单链表;
/*
单链表:
*/
typedef int ElemType;
typedef struct node{
ElemType data; //数据域
struct node * Next; //指针域
}slink; //结构体名 //建立单链表
slink *creslink(int n){
slink *head,*p,*s;
int i;
p=head=(slink *)malloc(sizeof(slink)); //创建头节点
for(i=1;i<=n;i++){
s=(slink *)malloc(sizeof(slink));
scanf("%d",&s->data);
p->Next=s;
p=s;
}
p->Next=NULL; //尾结点置空;
return head;
}
//求链表长度 ----使用n做累加值,求其链表的长度;
int getlen(slink * head){
slink *p;
int n;
p=head->Next;n=0;
while(p!=NULL){
n++;
p=p->Next;
}
return n;
}
//取元素操作
int getelem(slink *head,int i,ElemType *e){
slink *p;
int j;
if(i<1)return 0;
p=head->Next;j=1;
while(p!=NULL&&j<i){ //计算取出那个位置的值,也就是将P指定到位置。
p=p->Next;j++;
}
if(p==NULL)
return 0;
*e=p->data;
return 1;
}
//定位操作
slink * locate(slink *head,ElemType x){
int i;
slink *p;
p=head->Next;i=1;
while(p!=NULL&&p->data!=x){ //确定x的位置,将指针P抛出;
p=p->Next;i++;
}
return p;
}
//删除操作
int delete(slink * head,int i,ElemType *e){
slink * p,* q;
int j;
if(i<1) return 0;
p=head;j=0;
while(p->Next!=NULL&&j<i-1){ //确定出i的位置,
p=p->Next;j++;
}
if(p->Next==NULL)return 0;
q=p->Next; //删除元素,这里的最重要;
p->next=q->next;
*e=q->data;
free(q); //释放删除的元素空间
return 1;
} //插入元素
int insert(slink *head,int i,ElemType x){
slink *p,*q;
int j;
if(i<1)return 0;
p=head;j=0;
while(p!=NULL&&j<i+1){
p=p->Next;j++;
}
if(p==NULL)return 0;
q=(slink *)malloc(sizeof(slink)); //申请空间
q->data=x;
q->Next=p->Next; //相当于头插法;
p->Next=q;
return 1;
}
//输出操作
void list(slink *head){
slink *p;
p=head->Next;
while(p!=NULL){
printf("%4d",p->data);
p=p->Next;
}
printf("\n");
}