计算机数据线性结构,数据结构与算法一 线性结构(上)

数据结构核心名词解释

数据:程序的操作对象,用于描述客观事物.

特点:1>. 可以输入到计算机 2>. 可以被计算机处理

数据元素:组成数据的对象的基本单位.

数据对象:性质相同的数据元素的集合(类似于数组).

结构:数据元素之间不是独立的,存在特定的关系.这些关系即是结构.

数据结构:指的数据对象中的数据元素之间的关系.

展示在代码里面就是:

//声明一个结构体类型

struct Teacher{ //一种数据结构

char *name; //数据项--名字

char *title; //数据项--职称

int age; //数据项--年龄

};

struct Teacher t1; //数据元素;

struct Teacher tArray[10]; //数据对象;

逻辑结构与物理结构的区别

逻辑结构:数据与数据之间的逻辑关系.

集合结构:没有先后顺序、相互平等.

线性结构:数据与数据之间是一对一的关系.链表、数组、字典、队列、栈、字符串

树形结构:数据与数据之间是一对多的关系.

图形结构:数据与数据之间是多对多的关系.

物理结构:

顺序存储

链式存储

f2526d85ccd6

数据结构与算法.png

数据结构与算法之间的关系

算法设计要求:有输入/输出、有穷性、确定性、可行性

算法效率衡量方法:正确性、可读性、健壮性、时间效率高和储存量低

空间复杂度:

在考量算法的空间复杂度,主要考虑算法执行时所需要的辅助空间.

程序空间计算因素:

寄存本身的指令

常数

变量

输入

对数据进行操作的辅助空间

时间复杂度

大O表示法

用常数1取代运行时间中所有常数 3->1 O(1)

在修改运行次数函数中,只保留最高阶项 n^3+2 n^2+5 -> O(n^3)

如果在最高阶存在且不等于1,则去除这个项目相乘的常数 2n^3 -> n^3

时间复杂度术语:

常数阶

线性阶

平方阶

对数阶

立方阶

nlog阶

指数阶(不考虑) O(2^n)或者O(n!) 除非是非常小的n,否则会造成噩梦般的时间消耗. 这是一种不切实际的算法时间复杂度. 一般不考虑!

f2526d85ccd6

时间复杂度.png

常数阶时间复杂度计算 O(1)

/* 1. 常数阶时间复杂度计算 O(1) */

//1+1+1 = 3 O(1)

void testSum1(int n){

int sum = 0; //执行1次

sum = (1+n)*n/2; //执行1次

printf("testSum1:%d\n",sum);//执行1次

}

//1+1+1+1+1+1+1 = 7 O(1)

void testSum2(int n){

int sum = 0; //执行1次

sum = (1+n)*n/2; //执行1次

sum = (1+n)*n/2; //执行1次

sum = (1+n)*n/2; //执行1次

sum = (1+n)*n/2; //执行1次

sum = (1+n)*n/2; //执行1次

printf("testSum2:%d\n",sum);//执行1次

}

//x=x+1; 执行1次

void add(int x){

x = x+1;

}

线性阶时间复杂度O(n)

/*2.线性阶时间复杂度*/

//x=x+1; 执行n次 O(n)

void add2(int x,int n){

for (int i = 0; i < n; i++) {

x = x+1;

}

}

//1+(n+1)+n+1 = 3+2n -> O(n)

void testSum3(int n){

int i,sum = 0; //执行1次

for (i = 1; i <= n; i++) { //执行n+1次

sum += i; //执行n次

}

printf("testSum3:%d\n",sum); //执行1次

}

对数阶O(logn)

/*2的x次方等于n x = log2n ->O(logn)*/

void testA(int n){

int count = 1; //执行1次

//n = 10

while (count < n) {

count = count * 2;

}

}

平方阶时间复杂度O( n^2 )

//x=x+1; 执行n*n次 ->O(n^2)

void add3(int x,int n){

for (int i = 0; i< n; i++) {

for (int j = 0; j < n ; j++) {

x=x+1;

}

}

}

//n+(n-1)+(n-2)+...+1 = n(n-1)/2 = n^2/2 + n/2 = O(n^2)

//sn = n(a1+an)/2

void testSum4(int n){

int sum = 0;

for(int i = 0; i < n;i++)

for (int j = i; j < n; j++) {

sum += j;

}

printf("textSum4:%d",sum);

}

//1+(n+1)+n(n+1)+n^2+n^2 = 2+3n^2+2n -> O(n^2)

void testSum5(int n){

int i,j,x=0,sum = 0; //执行1次

for (i = 1; i <= n; i++) { //执行n+1次

for (j = 1; j <= n; j++) { //执行n(n+1)

x++; //执行n*n次

sum = sum + x; //执行n*n次

}

}

printf("testSum5:%d\n",sum);

}

立方阶O( n^3 )

void testB(int n){

int sum = 1; //执行1次

for (int i = 0; i < n; i++) { //执行n次

for (int j = 0 ; j < n; j++) { //执行n*n次

for (int k = 0; k < n; k++) {//执行n*n*n次

sum = sum * 2; //执行n*n*n次

}

}

}

}

线性表-关于顺序存储的实现(增删改查)

1.0 宏定义及顺序表结构设计

#define MAXSIZE 100

#define OK 1

#define ERROR 0

#define TRUE 1

#define FALSE 0

/* ElemType类型根据实际情况而定,这里假设为int */

typedef int ElemType;

/* Status是函数的类型,其值是函数结果状态代码,如OK等 */

typedef int Status;

/*线性结构使用顺序表的方式存储*/

//顺序表结构设计

typedef struct {

ElemType *data;

int length;

}Sqlist;

1.1 顺序表初始化

Status InitList(Sqlist *L){

//为顺序表分配一个大小为MAXSIZE 的数组空间

L->data = malloc(sizeof(ElemType) * MAXSIZE);

//存储分配失败退出

if(!L->data) exit(ERROR);

//空表长度为0

L->length = 0;

return OK;

}

1.2 顺序表的插入

/*

初始条件:顺序线性表L已存在,1≤i≤ListLength(L);

操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1

*/

Status ListInsert(Sqlist *L,int i,ElemType e){

//i值不合法判断

if((i<1) || (i>L->length+1)) return ERROR;

//存储空间已满

if(L->length == MAXSIZE) return ERROR;

//插入数据不在表尾,则先移动出空余位置

if(i <= L->length){

for(int j = L->length-1; j>=i-1;j--){

//插入位置以及之后的位置后移动1位

L->data[j+1] = L->data[j];

}

}

//将新元素e 放入第i个位置上

L->data[i-1] = e;

//长度+1;

++L->length;

return OK;

}

1.3 顺序表的取值

Status GetElem(Sqlist L,int i, ElemType *e){

//判断i值是否合理, 若不合理,返回ERROR

if(i<1 || i > L.length) return ERROR;

//data[i-1]单元存储第i个数据元素.

*e = L.data[i-1];

return OK;

}

1.4 顺序表删除

/*

初始条件:顺序线性表L已存在,1≤i≤ListLength(L)

操作结果: 删除L的第i个数据元素,L的长度减1

*/

Status ListDelete(Sqlist *L,int i){

//线性表为空

if(L->length == 0) return ERROR;

//i值不合法判断

if((i<1) || (i>L->length+1)) return ERROR;

for(int j = i; j < L->length;j++){

//被删除元素之后的元素向前移动

L->data[j-1] = L->data[j];

}

//表长度-1;

L->length --;

return OK;

}

1.5 清空顺序表

/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */

Status ClearList(Sqlist *L)

{

L->length=0;

return OK;

}

1.6 判断顺序表清空

/* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */

Status ListEmpty(Sqlist L)

{

if(L.length==0)

return TRUE;

else

return FALSE;

}

1.7 获取顺序表长度ListEmpty元素个数

int ListLength(Sqlist L)

{

return L.length;

}

1.8 顺序输出List

/* 初始条件:顺序线性表L已存在 */

/* 操作结果:依次对L的每个数据元素输出 */

Status TraverseList(Sqlist L)

{

int i;

for(i=0;i

printf("%d\n",L.data[i]);

printf("\n");

return OK;

}

1.9 顺序表查找元素并返回位置

/* 初始条件:顺序线性表L已存在 */

/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */

/* 若这样的数据元素不存在,则返回值为0 */

int LocateElem(Sqlist L,ElemType e)

{

int i;

if (L.length==0) return 0;

for(i=0;i

{

if (L.data[i]==e)

break;

}

if(i>=L.length) return 0;

return i+1;

}

2.0 客户端测试

Sqlist L;

ElemType e;

Status iStatus;

//1.1 顺序表初始化

iStatus = InitList(&L);

printf("初始化L后: L.Length = %d\n", L.length);

//1.2 顺序表数据插入

for(int j=1; j <= 5;j++){

iStatus = ListInsert(&L, 1, j);

}

TraverseList(L);

printf("插入数据L长度: %d\n",L.length);

//1.3 顺序表取值

GetElem(L, 5, &e);

printf("顺序表L第5个元素的值为:%d\n",e);

//1.4 顺序表删除第2个元素

ListDelete(&L, 2);

printf("顺序表删除第%d元素,长度为%d\n",2,L.length);

TraverseList(L);

//1.5 清空顺序表

iStatus = ClearList(&L);

printf("清空后,L.length = %d\n",L.length);

//1.6 判断List是否为空

iStatus=ListEmpty(L);

printf("L是否空:i=%d(1:是 0:否)\n",iStatus);

//1.8 TraverseList

for(int j=1; j <= 5;j++){

iStatus = ListInsert(&L, 1, j);

}

TraverseList(L);

线性表-关于链表(单链表)存储的设计(增删改查与头插法/尾插法)

2.0 宏定义及节点定义

#define ERROR 0

#define TRUE 1

#define FALSE 0

#define OK 1

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */

typedef int ElemType;/* ElemType类型根据实际情况而定,这里假设为int */

//定义结点

typedef struct Node{

ElemType data;

struct Node *next;

}Node;

typedef struct Node * LinkList;

2.1 初始化单链表线性表

Status InitList(LinkList *L){

//产生头结点,并使用L指向此头结点

*L = (LinkList)malloc(sizeof(Node));

//存储空间分配失败

if(*L == NULL) return ERROR;

//将头结点的指针域置空

(*L)->next = NULL;

return OK;

}

2.2 单链表插入

/*

初始条件:顺序线性表L已存在,1≤i≤ListLength(L);

操作结果:在L中第i个位置之后插入新的数据元素e,L的长度加1;

*/

Status ListInsert(LinkList *L,int i,ElemType e){

int j;

LinkList p,s;

p = *L;

j = 1;

//寻找第i-1个结点

while (p && j

p = p->next;

++j;

}

//第i个元素不存在

if(!p || j>i) return ERROR;

//生成新结点s

s = (LinkList)malloc(sizeof(Node));

//将e赋值给s的数值域

s->data = e;

//将p的后继结点赋值给s的后继

s->next = p->next;

//将s赋值给p的后继

p->next = s;

return OK;

}

2.3 单链表取值

/*

初始条件: 顺序线性表L已存在,1≤i≤ListLength(L);

操作结果:用e返回L中第i个数据元素的值

*/

Status GetElem(LinkList L,int i,ElemType *e){

//j: 计数.

int j;

//声明结点p;

LinkList p;

//将结点p 指向链表L的第一个结点;

p = L->next;

//j计算=1;

j = 1;

//p不为空,且计算j不等于i,则循环继续

while (p && j

//p指向下一个结点

p = p->next;

++j;

}

//如果p为空或者j>i,则返回error

if(!p || j > i) return ERROR;

//e = p所指的结点的data

*e = p->data;

return OK;

}

2.4 单链表删除元素

/*

初始条件:顺序线性表L已存在,1≤i≤ListLength(L)

操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1

*/

Status ListDelete(LinkList *L,int i,ElemType *e){

int j;

LinkList p,q;

p = (*L)->next;

j = 1;

//查找第i-1个结点,p指向该结点

while (p->next && j

p = p->next;

++j;

}

//当i>n 或者 i<1 时,删除位置不合理

if (!(p->next) || (j>i-1)) return ERROR;

//q指向要删除的结点

q = p->next;

//将q的后继赋值给p的后继

p->next = q->next;

//将q结点中的数据给e

*e = q->data;

//让系统回收此结点,释放内存;

free(q);

return OK;

}

2.5 依次对L的每个数据元素输出

/* 初始条件:顺序线性表L已存在 */

/* 操作结果:依次对L的每个数据元素输出 */

Status ListTraverse(LinkList L)

{

LinkList p=L->next;

while(p)

{

printf("%d\n",p->data);

p=p->next;

}

printf("\n");

return OK;

}

2.6 将L重置为空表

/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */

Status ClearList(LinkList *L)

{

LinkList p,q;

p=(*L)->next; /* p指向第一个结点 */

while(p) /* 没到表尾 */

{

q=p->next;

free(p);

p=q;

}

(*L)->next=NULL; /* 头结点指针域为空 */

return OK;

}

3.1 单链表前插入法

/* 随机产生n个元素值,建立带表头结点的单链线性表L(前插法)*/

void CreateListHead(LinkList *L, int n){

LinkList p;

//建立1个带头结点的单链表

*L = (LinkList)malloc(sizeof(Node));

(*L)->next = NULL;

//循环前插入随机数据

for(int i = 0; i < n;i++)

{

//生成新结点

p = (LinkList)malloc(sizeof(Node));

//i赋值给新结点的data

p->data = i;

//p->next = 头结点的L->next

p->next = (*L)->next;

//将结点P插入到头结点之后;

(*L)->next = p;

}

}

3.2 单链表后插入法

/* 随机产生n个元素值,建立带表头结点的单链线性表L(后插法)*/

void CreateListTail(LinkList *L, int n){

LinkList p,r;

//建立1个带头结点的单链表

*L = (LinkList)malloc(sizeof(Node));

//r指向尾部的结点

r = *L;

for (int i=0; i

//生成新结点

p = (Node *)malloc(sizeof(Node));

p->data = i;

//将表尾终端结点的指针指向新结点

r->next = p;

//将当前的新结点定义为表尾终端结点

r = p;

}

//将尾指针的next = null

r->next = NULL;

}

客户端测试

Status iStatus;

LinkList L1,L;

struct Node *L2;

ElemType e;

printf("L1.data=%d,L2.data=%d\n",L1->data,L2->data);

//2.1 单链表初始化

iStatus = InitList(&L);

printf("L 是否初始化成功?(0:失败,1:成功) %d\n",iStatus);

//2.2 单链表插入数据

for(int j = 1;j<=10;j++)

{

iStatus = ListInsert(&L, 1, j);

}

printf("L 插入后\n");

ListTraverse(L);

//2.3 单链表获取元素

GetElem(L,5,&e);

printf("第5个元素的值为:%d\n",e);

//2.4 删除第5个元素

iStatus = ListDelete(&L, 5, &e);

printf("删除第5个元素值为:%d\n",e);

ListTraverse(L);

//3.1 前插法整理创建链表L

iStatus = ClearList(&L);

CreateListHead(&L, 20);

printf("整理创建L的元素(前插法):\n");

ListTraverse(L);

//3.2 后插法整理创建链表L

iStatus = ClearList(&L);

CreateListTail(&L, 20);

printf("整理创建L的元素(后插法):\n");

ListTraverse(L);

注: 1 2 3 4 5 将6插入到第三个,实际上是打破2和3个关系插入6,你需要找到i-1也就是2号位置,将2号位置的next指向当前节点,并将当前节点的next指向2号位的下一个节点. 结果是1 2 6 3 4 5.

1 2 3 4 5 删除第三个,实际上是也是打破2 3的关系,找到i - 1 也就是2号的位置,将2号位置的next指向 3号位置的next也就是4号位置,并且将3号位置释放. 结果是1 2 4 5.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值