数据结构基础

【1】逻辑结构

逻辑结构:数据与数据之间的联系和规律 逻辑关系

数据之间的关系:

1.线性关系-----》线性结构-----》一对一------》顺序表(数组)、链表(指针)、 栈、队列(队头出队、队尾入队)

2.层次关系 ------> 树形结构 -----> 一对多 ------> 树

3、网状关系 ------> 图状结构 -----> 多对多 ------> 图

【2】存储结构

存储类型

存储结构:数据的存储结构指的是数据的逻辑结构在计算机存储器中的映象(或表示)。存储结构是通过计算机语言所编制的程序来实现的,因而是依赖于具体的计算机语言。int a ,int st[] ; 结构体;

1、顺序存储结构 (顺序表)

数组:将数据结构中各元素按照其逻辑顺序存放于存储器一片连续的存储空间中(如c语言的一维数组)

2、链式存储结构(栓狗的链子)

特点:数据在内存当中存储是不连续的,通过指针将数据联系在一起

3、索引存储结构 (手机通讯)

提高查找速度

索引表 + 数据文件

姓氏+ 地址 名字 + 电话号码

4、散列存储结构(蜂巢取快递)

数据在存储的时候与关键码之间存在某种对应关系,存的时候按照对应关系存,取的时候按照对应关

【3】操作 (运算):

增删改查

图书管理系统

查找某个图书信息

新买一本书,增加到数据中

书丢了,删除

书名写错了,修改

【4】算法

算法衡量标准

解决问题的思想办法 (冒泡排序、选择排序、快速排序)

1.1 算法与程序

算法:解决问题的思想办法

程序:用计算机语言对算法的具体实现

1.2 算法与数据结构

算法 + 数据结构 = 程序 (进程、程序)

算法的设计: 取决于选定的逻辑结构(线性、参差、网状)

算法的实现: 依赖于采用的存储结构 (顺序、链式、索引、散列)

1.3 算法的特性

(1)有穷性 //算法的执行步骤是有限的

(2)确定性 //算法的每一个步骤,无二义性 ,没有歧义

(3)可行性 //算法能够在有限的时间内完成

(4)输入 //一个算法可以有一个或多个输入 5、10 、20

(5)输出 //一个算法可以有一个或多个输出

1.4 如何评价一个算法的好坏

(1)消耗时间的多少 //越少越好

(2)消耗内存的多少 //越小越好

(3)程序的可读性 、维护、调试 、移植 好坏

传感器-》模拟量-ADC-》数字量

1.5 时间复杂度(程序运行的速度)

定义:算法的可执行语句重复执行的频度和

语句频度: 算法中可执行语句重复执行的次数

通常时间复杂度用一个问题规模函数来表达 :

T(n) = O(f(n))

T(n) :问题规模的时间函数 ,n:代表的是问题的规模 输入数据量的大小

举例: 对一个int a[100];进行冒泡排序 100 == n

O :时间数量级

f(n) :算法中可执语句重复执行的次数 ,用问题规模n的某个函数f(n)来表达

例子1:

求 1 + 2 + 3 + 4 + ....... n 的和

  • 算法一

int sum = 0; n = 100 100次

int i;

for(i = 1; i <= n; i++) n = 1000 1000次

{

sum += i;

} f(n) = n;

T(n) = O(n);

  • 算法二

int sum = n*(n+1)/2 n = 100 1次

n = 1000 1次

f(n) = 1;

T(n) = O(1);

例2:

int i,j;

for(i = 0; i < n; i++)//外循环循环一次,内循环跑一圈 n

{

for(j = 0; j < n; j++)// n

{

printf("hello world!!\n"); // n * n

}

}

f(n) = n*n;

T(n) = O(n^2);

例3

int i,j;

for(i = 0; i < n; i++)//外循环循环一次,内循环跑一圈 n

{

for(j = 0; j <= i; j++)//内循环的次数与i的值相关

{

printf("hello world!!\n");

}

}

i的值 循环次数

i == 0 1

i == 1 2

i == 2 3

...

...

i == n-2 n-1

i == n-1 n

循环次数 = 1 + 2 + 3 + 4 + ..... + n

f(n) = n*(n+1)/2

f(n) = n^2/2 + n/2

//最高项n^2 ,只保留最高项,其它项舍去 f(n) = n^2/2 ,再除以最高项系数 除以1/2 f(n) = n^2

//经过处理之后 :T(n) = O(n^2)

计算大O的方法

1、根据问题规模n写出表达式 f(n)

2、只保留最高项,其它项舍去

3、如果最高项系数不为1,除以最高项系数

如果有常数项,将其置为1 n^0 *8 。//当f(n)的表达式中只有常数项的时候,有意义 f(n) = 8 -》T(n)=O(1)

f(n) = 3*n^5 + 2*n^3 + 6*n + 10 *n^0 //10 代表的是常数项;//3* 2* 6* 系数项

//最高项指的是指数 ^5 ^3 ^1 最高项为 n^5

T(n) = O(n^5)

f(n) = n^0 *8;//最高项 n^0

T(n) = O(1);

作业:计算冒泡排序以及选择排序的时间复杂度

【5】线性表-》顺序表

线性表介绍

线性表包括:顺序表 链表(单向链表 双向链表 单向循环链表 双向循环链表) 栈 队列

1.逻辑结构:线性结构

2.存储结构://两种方式选择

1)顺序存储---》数组

2)链式存储---》链表

3.线性表的特点:

                一对一,每个节点最多一个前驱和一个后继

        首尾节点特殊:首节点无前驱,尾节点无后继

顺序表介绍:

逻辑结构:线性结构

存储结构:顺序存储,在内存当中的存储是连续的

顺序表的特点:1.顺序表在内存当中是连续存储的

                         2.顺序表的长度是固定的 #define N 5

                        3.顺序表查找(下标)数据的时候方便的,插入(last~post后移动一位)和

                        (post+1~last前移动一位)麻烦

命名法则:

        大驼峰:InsertInto

        小驼峰: insertinto

        加下划线: insert_into

        见名知意;

顺序表的结构体:

        #define N 10 (顺序表的长度是固定的)

        typedef int datatype; (重命名一个数据类型的名字)

        typedef struct sequencelist (sequence顺序,list表)

        {

                datatype data【N】; (数据域)

                int last (last代表有效元素的最后一个下标)

        }sequencelist_t; (type 类型)

顺序表函数代码

1.创建一个空的表

2.向表中的指定位置插入数据

3.判断顺序表的状态

4.遍历打印顺序表中的数据

5.删除指定位置的数据

6.查找顺序表中的数据,找到返回下标

7.修改顺序表中指定位置的数据

8.清空顺序表

9.集合A: 1 3 5 7 //顺序表A

集合B:5 7 9 11 //顺序表B

求AUB:1 3 5 7 9 11

#include<stdio.h>
#include<stdlib.h>
#define N 20
typedef int typedata;
typedef struct Z
{
    typedata data[N];
    int last;
}type;

int full(type *p);
int insert(type *p,int post ,int data)//插入
{
    if (post<0 || post>p->last+1 || full(p))
    {
        printf("insert failed\n");
        return -1;
    }
    for (int i = p->last; i < post; i++)
    {
        p->data[i+1]=p->data[i];
    }
    p->last++;
    p->data[post]=data;
    return 0;
}

int show(type *p)//打印顺序表中的数据
{
    for (int i = 0; i <= p->last; i++)
    {
        printf("%d ",p->data[i]);
    }
    putchar(10);
    return 0;
}

int find(type *p,int data)//通过数据查找表中的内容
{
    for (int i = 0; i <=p->last; i++)
    {
        if (p->data[i]==data )
        {
            return i;
        }

    }
    return -1;

}

int merge(type *p,type *q)//合并
{
    for (int i = 0; i <=q->last; i++)
    {
        if (find(p,q->data[i])==-1)//查找p顺序表中的内容有没有和q表中一样的内容,不一样插入到p表中
        {
            insert(p,p->last+1,q->data[i]);
        }

    }
    return 0;

}

int full(type *p)
{
    return p->last==N-1;//last=N-1代表 表满
}

int main(int argc, char const *argv[])
{
    type *sheet1=(type *)malloc(sizeof(type));//开辟一个p顺序表
    type *sheet2=(type *)malloc(sizeof(type));//开辟一个q顺序表

    return 0;
}

【6】线性表-》链表

链表介绍

链表包括:单向链表(有头单向链表 无头单向链表) 双向链表 双向循环链表

逻辑结构:线性结构

存储结构:链式存储

操作:增删改查

链表特点:长度不固定,增加和删除简单

链表的结构体:

typedef int datatype

typedef struct linklist (link链式 list表)

{

        datatype data; (数据域)

        struct linklist *next (指针域 存放下一个节点的地址)

 }linklist_t,*linklist_node_t; (linklist_node_t)==(linklist_t *)

遍历无头单向链表

链表中的每一个节点的数据域和指针域都是有效的

遍历有头单向链表

链表中的第一个头节点的数据域无效,但指针域有效

有头单向链表的操作思想

一、插入

解题思想:

1、先遍历找到要插入节点的前一个节点,假设这个节点为A;A的下一个节点为B;

将C插入A与B之间;

2、先让C的指针域指向B;

3、再让A的指针域指向C;

注意:顺序不可以调换

、删除

解题思想:

1、先遍历找到要删除节点的前一个节点,假设为A;

2、找一个临时指针指向要删除的节点;

3、将A的指针域指向删除节点的下一个节点;

三、倒置

解题思想:

1、将头节点与当前链表断开,断开前保存头节点的下一个节点,保证后面链表能找得到,定义一个q保存头节点的下一个节点,断开后前面相当于一个有头的空链表,后面是一个无头的单向链表

2、遍历无头链表的所有节点,将每一个节点当做新节点头插到有头空链表中(每次插入到头节点的下一个节点位置)

四、清空链表

单向链表函数代码

1.开辟一个头节点(有头单向链表)

2.插入新节点

3.遍历单向链表

4.求单向链表的长度

5.删除单向链表中指定位置的节点

6.判断链表是否为空

7.修改指定位置的数据 post 被修改的位置 data修改成的数据

8.查找指定数据出现的位置 data被查找的数据

9.删除查找到的节点,data是查找的数据

10.链表转置

11.清空链表

12:

递增有序的链表A 1 3 5 7 9 10

递增有序的链表B 2 4 5 8 11 15

新链表:1 2 3 4 5 5 7 8 9 10 11 15

将链表A和B合并,形成一个递增有序的新链表

#include <stdio.h>
#include <stdlib.h>
typedef struct L
{
    int data;
    struct L *next;

} un_linked_list, *linked_list;

un_linked_list *creat() //开辟一个空的链表
{
    un_linked_list *head = (un_linked_list *)malloc(sizeof(un_linked_list));
    if (NULL == head)
    {
        printf("malloc failed\n");
        return NULL;
    }
    head->next = NULL;
    return head;
}

//计算链表的长度
int len(un_linked_list *p)
{
    int len = 0;
    while (p->next != NULL)
    {
        p = p->next;
        len++;
    }
    return len;
}

int insert(un_linked_list *p, int post, int data)
{
    if (post < 0 || post > len(p))
    {
        printf("insert failed\n");
        return -1;
    }

    un_linked_list *a = (un_linked_list *)malloc(sizeof(un_linked_list)); //开辟新节点
    if (NULL == a)
    {
        printf("malloc failed\n");
        return -1;
    }
    a->data = data; //新节点根据参数初始化
    a->next = NULL;
    for (int i = 0; i < post; i++) //找到要插入节点的上一个节点
    {
        p = p->next;
    }
    a->next = p->next;
    p->next = a;
    return 0;
}
int show(un_linked_list *p)
{
    while (p->next != NULL)
    {
        p = p->next;
        printf("%d ", p->data);
    }
    putchar(10);
    return 0;
}
//合并
void combineAB(un_linked_list *pa, un_linked_list *pb)
{
    un_linked_list *ptail = pa;//ptail指向最后一个节点
    pa = pa->next;//移动到第一个有效节点
    pb = pb->next;//有头单向链表头节点数据域没有内容,不是有效节点
    while (pa != NULL && pb != NULL)
    {
        if (pa->data<=pb->data)
        {
            ptail->next=pa;
            pa=pa->next;
            ptail=ptail->next;

        }
        else
        {
            ptail->next=pb;
            pb=pb->next;
            ptail=ptail->next;
        }
    }
    if (pa==NULL)
    {
        ptail->next=pb;
    }
    else
    {
        ptail->next=pa;
    }
    
    
}

int main(int argc, char const *argv[])
{
    un_linked_list *p = creat();
    un_linked_list *p1 = creat();

    insert(p, 0, 1);
    insert(p, 1, 3);
    insert(p, 2, 5);
    insert(p, 3, 7);
    insert(p, 4, 9);
    insert(p, 5, 10);
    show(p);
    insert(p1, 0, 2);
    insert(p1, 1, 4);
    insert(p1, 2, 5);
    insert(p1, 3, 8);
    insert(p1, 4, 11);
    insert(p1, 5, 15);
    show(p1);
    combineAB(p,p1);
    show(p);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值