数据结构*

数据结构

有一种或多种特定关系的数据元素的集合
DS=(D,R);
D:数据集合
R:关系集合

数据:

数据:信息的载体
数据元素:数据的组成单位,一般作为一个整体考虑
数据项:数据元素的组成单位
数据对象:用特定结构体定义的数组
数据类型:对数据元素取值范围与运算的限定
struct stu {
int age;
char name[32];
};
struct stu zc;//数据元素
zc.age=18;
strcpy(zc.name,“zhancgheng”);//数据项
struct stu zc【32】;//数据对象

关系:

逻辑结构:

线性:一对一的关系,除了第一个数据元素没有唯一前驱,最后一个数据元素没有唯一后继,其余的数
据元素都有唯一前驱和唯一后继
表、栈、队列
非线性
树:一对多的关系,除了第一个数据元素没有唯一前驱,其余的数据元素都有唯一前驱并且可以有多个
后继
图:多对多的关系

存储结构:

顺序存储:类似于数组,把逻辑上相邻的数据元素在物理地址上存储也相邻
链式存储:把逻辑上相邻的数据元素在物理地址上可以不相邻
数据域+指针域
数据域:存放数据
指针域:存放数据元素的下一个数据元素的地址
索引存储:在存储数据的同时,建立一个附加的索引表,即索引存储结构=数据文件+索引表。
散列存储:根据数据元素的特殊字段(称为关键字key),计算数据元素的存放地址,然后数据元素按地址
存放,所得到的存储结构为散列存储结构(或Hash结构)。

运算:

增、删、改、查、判空、判满、清空、销毁、排序

算法:是一个有穷规则(或语句、指令)的有序集合

冒泡排序、选择排序、插入排序、希尔排序、快速排序。。。。
怎么才是一个好的算法:
空间复杂度: 设算法对应问题的体积(或规模)为n,执行算法所占存储空间的量级为D(n),则D(n)为算
法的空间复杂度

9 int printN(int n)
10 {
11 if(n)
12 {
13 printN(n-1);
14 printf("%d\n",n);
15 }
16 return 0;
17 }//不好的算法,占用太多的空间地址
18 #if 0
19 int printN(int n)
20 {
21 int i=0;
22 for(i=1;i<=n;i++)
23 {
24 printf("%d\n",i);
25 }
26 return 0;
27 }
28 #endif
29 int main(int argc, char *argv[])
30 {
31 int n;
32 scanf("%d",&n);
33 printN(n);
34
35 return 0;
36 }

时间复杂度:
第一步,算出所有语句的执行次数,4n3+2n2+n
第二步,取最高次项4n³
第三步,去除最高次项的系数n³

int i,j,z;
for(i=0;i<n;i++)//n+1
{
for(j=0;j<n;j++)//n*(n+1)
{
for(z=0;z<n;z++)//n*n*(n+1)
{
printf("%d",z);//n*n*n
}
}

算法和数据结构的关系:依存关系,没有算法只谈数据结构,数据都是死的,算法是活的,抛开数据结
构,只谈算法,没有依赖的数据支撑,空谈

线性表:

顺序表

/*===============================================
* 文件名称:sqlist.c
* 创 建 者:
* 创建日期:2023年03月06日
* 描 述:
================================================*/
#include "sqlist.h"
//创建顺序表
sq_pnode create_sqlist()
{
sq_pnode L = (sq_pnode)malloc(sizeof(sq_node));
if(NULL == L)
{
printf("create is error\n");
}
L->len=0;//顺序表长度初始化为0
return L;
}
//判满
int full_sqlist(sq_pnode L)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(L->len == N)
return 1;
else
return -1;
}
//判空
int empty_sqlist(sq_pnode L)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(0 == L->len)
return 1;
else
return -1;
}
//插入
int insert_sqlist(sq_pnode L,int pos,data_t data)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
//判满
if(1==full_sqlist(L))
{
printf("L is full\n");
return -1;
}
if(pos<0||pos>N)
{
printf("pos is eroor\n");
return -1;
}
int i;
//把插入的位置空出来,插入位置后面所有数据元素往后移动一个,最后一个开始
for(i=L->len-1;i>=pos;i--)
{
L->buf[i+1]=L->buf[i];
}
L->buf[pos]=data;//给插入的元素赋值
L->len++;
return 0;
}
//打印顺序表
int show_sqlist(sq_pnode L)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(1 == empty_sqlist(L))
{
printf("L is empty\n");
return -1;
}
int i;
for(i=0;i<L->len;i++)
{
printf("buf[%d]=%c\n",i,L->buf[i]);
}
return 0;
}
//删除
int delete_sqlist(sq_pnode L,int pos)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(1 == empty_sqlist(L))
{
printf("L is empty\n");
return -1;
}
if(pos<0||pos>L->len)
{
printf("pos is error\n");
return -1;
}
int i;
for(i=pos;i<L->len;i++)//找到删除的位置,把后面的值依次往前赋
{
L->buf[i]=L->buf[i+1];
}
L->len--;
return 0;
}
//根据元素查位置
int search_sqlist(sq_pnode L,data_t data)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(1 == empty_sqlist(L))
{
printf("L is empty\n");
return -1;
}
int i;
for(i=0;i<L->len;i++)
{
if(data == L->buf[i])
return i;
}
puts("没有这个元素");
return 0;
}
data_t search_sqlist2(sq_pnode L,int pos)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(1 == empty_sqlist(L))
{
printf("L is empty\n");
return -1;
}
if(pos<0||pos>L->len)
{
printf("pos is error\n");
return -1;
}
return L->buf[pos];
}
//清空
int clear_sqlist(sq_pnode L)
{
if(NULL == L)
{
printf("L is NULL\n");
return 0;
}
if(1 == empty_sqlist(L))
{
printf("L is empty\n");
return -1;
}
int i;
while(1)
{
delete_sqlist(L,0);
作业:
逆序打印顺序表
从小到大排序顺序表
if(L->len == 0)
{ printf("L is empty333\n");
return 0;
}
}
}
//摧毁
int destory_sqlist(sq_pnode *L)
{
if(NULL == *L)
{
printf("L is NULL\n");
return 0;
}
free(*L);
*L=NULL;
return 0;
}

数据结构-第二天

复习:

数据、数据元素,数据项,数据对象

结构:

逻辑:线性、非线性

存储:顺序、链式

运算:增删改查、判空、判满、清空、摧毁、排序

算法:时间复杂度和空间复杂度

顺序表:

插入、删除、查、改、判空、判满、清空和摧毁、打印

7 #include <stdio.h>
  8 #define A char *
  9 typedef  char*  Z;
 10 int main(int argc, char *argv[])
 11 {
 12     A a,b;
 13     Z c,d;
 14     printf("a=%ld\n",sizeof(a));
 15     printf("b=%ld\n",sizeof(b));
 16     printf("c=%ld\n",sizeof(c));
 17     printf("d=%ld\n",sizeof(d));
 18     return 0;
 19 }

链表:一对一,逻辑上相邻的数据元素物理地址可以不相邻

结点=数据域+指针域

数据域:放的是数值数据

指针域:放的是当前数据元素的下一个数据元素的首地址

头结点:没有存放数据,只是为了方便操作链表

练习:根据数据改数据

有余力的同学可以去写双向循环链表

栈:

顺序栈:在满足一对一,逻辑上相邻,物理位置也相邻,还要满足先进后出

作业:把顺序栈的写完

数据结构-第三天

链表:节省空间,插入和删除简单

顺序表:浪费空间,改和查简单

链栈:链表的特殊的一种形式,遵循先进后出的原则

/*===============================================
*   文件名称:linkstack.c
*   创 建 者:     
*   创建日期:2023年03月08日
*   描    述:
================================================*/
#include "linkstack.h"
//创建
lsl_pnode create_linkstack()
{
    lsl_pnode S = (lsl_pnode)malloc(sizeof(lsl_node));
    if(NULL == S)
    {
        printf("create\n");
        return NULL;
    }
    S->next = NULL;
    return S;
}
//判空
int empty_linkstack(lsl_pnode S)
{
    if(NULL == S)
    {
        printf("S is NULL\n");
        return -1;
    }
    if(NULL == S->next)
        return 0;
    else
        return 1;
}

//求长度
int len_linkstack(lsl_pnode S)
{
    if(NULL == S)
    {
        printf("S is NULL\n");
        return -1;
    }
    if(0 == empty_linkstack(S))
    {
        printf("S is empty\n");
        return -1;
    }
    int len=0;
    S=S->next;
    while(S)
    {
        S=S->next;
        len++;
    }
    return len;
}
//打印
int show_linkstack(lsl_pnode S)
{
    if(NULL == S)
    {
        printf("S is NULL\n");
        return -1;
    }
    if(0 == empty_linkstack(S))
    {
        printf("S is empty\n");
        return -1;
    }
    S=S->next;
    while(S)
    {
        printf("%c->",S->data);
        S=S->next;
    }
    puts("");
    return 0;
}

//入栈
int in_linkstack(lsl_pnode S,lsl_data_t data)
{
    if(NULL == S)
    {
        printf("S is NULL\n");
        return -1;
    }
    //创建新结点
    lsl_pnode p = create_linkstack();
    p->data = data;
    p->next = S->next;
    S->next = p;
    return 0;
}

//出栈
int out_linkstack(lsl_pnode S)
{
    if(NULL == S)
    {
        printf("S is NULL\n");
        return -1;
    }
    if(0 == empty_linkstack(S))
    {
        printf("S is empty\n");
        return -1;
    }
    lsl_pnode p = create_linkstack();
    p=S->next;
    printf("data=%c\n",p->data);
    S->next=p->next;
    free(p);
    p=NULL;
    return 0;
}

队列:先进先出

线性队列:一对一,只能从队头出,只能从队尾进

循环队列:重复使用同一片空间地址

1、为什么要空一个出来,为什么是(tail+1)%N

为了区别判空和判满的条件

2、为什么判满不是tail==N-1

单向队列确实可以,但是循环队列不能满足所有情况

/*===============================================
*   文件名称:queue.c
*   创 建 者:     
*   创建日期:2023年03月08日
*   描    述:
================================================*/
#include "queue.h"

//创建
que_pnode create_queue()
{
    que_pnode Q = (que_pnode)malloc(sizeof(que_node));
    if(NULL == Q)
    {
        printf("create\n");
        return NULL;
    }
    Q->head = Q->tail = 0;
    return Q;
}

//判空
int empty_queue(que_pnode Q)
{
    if(NULL == Q)
    {
        printf("Q is NULL\n");
        return -1;
    }
    if(Q->head == Q->tail)
        return 0;
    else
        return 1;
}
//判满
int full_queue(que_pnode Q)
{

    if(NULL == Q)
    {
        printf("Q is NULL\n");
        return -1;
    }
    if((Q->tail+1)%N == Q->head)
        return 0;
    else
        return 1;
}

//入队
int in_queue(que_pnode Q,que_data_t data)
{
    if(NULL == Q)
    {
        printf("Q is NULL\n");
        return -1;
    }
    if(0 == full_queue(Q))
    {
        printf("Q is full\n");
        return -1;
    }
    Q->buf[Q->tail]=data;//队尾赋值
    Q->tail = (Q->tail+1)%N;//队尾往下移动一个,考虑插入最后一个后要变为队头,从头开始入队
    return 0;
}
//打印
int show_queue(que_pnode Q)
{
    if(NULL == Q)
    {
        printf("Q is NULL\n");
        return -1;
    }
    if(0 == empty_queue(Q))
    {
        printf("Q is empty\n");
        return -1;
    }
    int i;
    for(i=Q->head;i!=Q->tail;i++)
    {
        printf("%c-",Q->buf[i]);
    }
    
            
    puts("");

    return 0;
}
//出队b-c-d-e-
que_data_t out_queue(que_pnode Q)
{
    if(NULL == Q)
    {
        printf("Q is NULL\n");
        return -1;
    }
    if(0 == empty_queue(Q))
    {
        printf("Q is empty\n");
        return -1;
    }
    que_data_t data = Q->buf[Q->head];
    Q->head=(Q->head+1)%N;
    return data;
}

链式队列:

数据结构-第四天

复习:

线性结构:(全部都掌握)

一对一,第一个数据元素没有前驱,最后一个后继,其余的都有唯一前驱和后继

表:线性结构,无特殊要求

顺序:查询和修改比较方便,定长浪费空间

链式:插入和删除比较方便,空间灵活

栈:线性结构,必须要满足先进后出原则 ,出栈和入栈都从栈顶开始

顺序:定长浪费空间

链式:空间灵活

队列:线性结构,同时要满足先进先出,出队只能从队头出,入队只能从队尾入

顺序:定长浪费空间

链式:空间灵活

非线性结构:

树:

1、树的概念:

树(Tree)是n(n≥0)个节点的有限集合T,它满足两个条件 :
有且仅有一个特定的称为根(Root)的节点;
其余的节点可以分为m(m≥0)个互不相交的有限集合T1、T2、……、Tm,其中每一个集合又是一棵树,并称为其根的子树(Subtree)

层次:树从根开始为第一层,后面依次递增

度:要看有多少个后继,一棵树的度数是指该树中节点的最大度数。

父节点:子节点的上一级(要有后继),根节点没有父节点

子节点:有且只有一个父节点

叶子节点:没有后继的节点

兄弟节点:同一个节点的子节点

孙子节点和祖先节点:两个节点之间有一层或多层

2、树的逻辑:

树中任何节点都可以有零个或多个直接后继节点(子节点),但至多只有一个直接前趋节点(父节点),根节点没有前趋节点,叶节点没有后继节点。

3、二叉树(重点)

概念:由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成

性质:

二叉树第i(i≥1)层上的节点最多为2i-1个。
深度为k(k≥1)的二叉树最多有2k-1个节点。
在任意一棵二叉树中,树叶的数目比度数为2的节点的数目多一。

分类:

满二叉树(完美二叉树):深度为k(k≥1)时有2k-1个节点的二叉树。

完全二叉树:只有最下面两层有度数小于2的节点,且最下面一层的叶节点集中在最左边的若干位置上

满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树

完全二叉树就是满二叉树从右往左,从下往上依次减

遍历:

层次遍历:一层一层遍历

先序遍历:根左右

中序遍历:左根右

后序遍历:左右根

存储结构:

顺序:

链式:

作业:写完树的所有遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值