数据结构与算法笔记整理---1(郝兵)

0.什么是数据结构和算法

数据结构 = 个体的存储(数据) +   个体关系的存储(数据结构)

解决一个问题(模拟一个问题) =  一个个不可再分的个体 +  个体与个体之间的关系  +  解决问题的算法

算法 = 对数据的操作方式(解题的方法和步骤)

 

1.数据结构的地位(软件最核心课程)

各种语言中的堆栈等概念。

操作系统中的某些概念。

数据库中的字段 记录 表等概念。

程序 = 数据的存储 +  数据的操作 + 可以被计算机执行的语言

 

衡量算法的标准

1.时间复杂度
    大概程序要执行的次数(硬件不断升级,衡量时间没有意义,次数越少,效率越高)
2.空间复杂度
    算法执行的过程中大概所占用的最大内存
3.难易程度(可读性)
    别人是否可以理解你的算法
4.健壮性
    对于非法数据的承受能力

 

2.预备知识-指针

数据结构的基础:链表(所以语言实现要有指针)

指针:

指针的重要性:

    指针是C语言的灵魂

定义:

    内存单元的编号

指针:

    指针就是地址,地址就是指针

    指针变量是存储指针的变量

int a[5]={0};

3[a]与a[3]的效果是相同的,3只是偏移地址,而a指向数组的的第一个元素。

所有的指针只占四个字节

结构体:

动态内存的分配和释放

3.如何通过函数修改实参的值

只能通过地址(指针)来修改实参的值
指向指针的指针

int i=10;
int *p=&i;
void f(int *p)
{
    .....
}         //修改指针指向的变量的值

void  f(int  **p)
{
    .....
}          //修改指针变量的值

4.动态内存分配概述

malloc :

int len;
printf("请输入你需要分配的的数组长度:len =");
scanf("%d",len);
int *pArr=( int * )malloc(  sizeof(int) * len ); //   只返回第一字节的地址
pArr[1]=10;  //a[1]=4;
*pArr=4;    //类似于 a[0]=10;


free(pArr);   //把pArr所代表的动态的分配的20个字节内存释放
  

 

5.跨函数使用内存

函数调用时分配的内存在函数调用完成之后就被释放了,如果想使用调用过的函数的内存,就不能依靠静态内存分配,而要使用动态内存分配,动态内存分配在调用函数过后并不会被释放,只有作者通过手工 free() 进行释放。

内存泄露:内存忘记释放越用越少。(系统越用越慢)

应用:一个函数创建链表,另一个函数使用链表,用的也是这个“跨函数使用内存”。

 

6.数据结构复习

数据结构 = 个体的存储(数据) +   个体关系的存储(数据结构)

解决一个问题(模拟一个问题) =  一个个不可再分的个体 +  个体与个体之间的关系  +  解决问题的算法

算法 = 对数据的操作方式(解题的方法和步骤)

对于不同的数据存储结构,操作数据的方式(算法)是不一样的。

 

7.结构体的使用概述

struct Student
{
    int sid;
    char  name[200];
    int age;
};

struct Student st;   //已经分配好了结构体变量的空间
struct Student st ={1000,"zhangsan",20};    // struct Student 是变量名,st 是变量
printf("%d  %s  %d\n",st.sid,st.name,st.age);     //结构体变量的名字加点访问结构体变量成员

为什么出现结构体:很多事物有着很多属性,一个学生的属性所需要的数据类型有很多,所以要用不同的数据类型组成一个新的数据类型。(普通的基本类型无法满足复杂数据的要求)

指向结构体的指针:
    struct student  *pst;
    pst =&st;
    pst->sid=99;    // pst->sid 等价于(*pst).sid   等价于  st.sid

如何使用结构体:
        两种方式:
                   struct Student st ={1000,"zhangsan",20};
                    struct Student *pst=&st;
            1.  st.sid
            2.pst->sid   //pst所指向的结构体变量中的Sid成员

注意事项:
            结构体变量不能加减乘除,但能够相互赋值
            普通结构体变量和结构体指针变量作为函数传参的问题

用形参的方式传递参数,耗费空间和时间,形参传递时直接在内存中找到一块临时空间,把变量复制进去,函数完成之后在回收内存空间



8.链表的重要性

链表承接了,树和图的基础。

 

9.typedef   (给数据类型取一个新的名字)

typedef int zheng;   //为int类型再取一个名字;zheng 等价于 int


typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}ST;     // 为Student结构体类型在定义一个新名字;


typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}* PST;   //   PST  相当于struct Student *


typedef struct Student
{
    int sid;
    char name[100];
    char sex;
}*PST,ST;    //同时取两个名字

连续存储数组的算法演示

模块一:线性结构【把所有的节点(数组的元素)用一根直线穿起来】

            连续存储 [数组]

 

            离散存储 [链表]

            

            线性结构的常见应用之一: 栈

 

            线性结构的常见应用之一:队列(和时间有关的操作)

 

 

范型:存储不一样,操作也一样。

            

10.链表的定义:

    离散存储【链表】:

    n个结点离散分配

    彼此通过指针相连接

    每个节点只有一个后续节点和前驱结点,首节点(第一个有效的节点)没有前驱节点,尾节点(最后一个有效的节点)没有后续节点。

    头结点:(第一个有效节点之前的节点,头结点不存放有效数据)方便对链表的操作(增删改查)头结点的数据类型与后面每一个节点的数据类型是一样的

    头指针:指向头节点的指针变量

    尾指针:指向尾节点的指针变量

11.链表的分类:

   单链表:

   双链表:每个节点有两个指针域(尾节点有一个指针区域)

   循环链表:能通过任何一个节点能找到其他所有节点

   非循环链表:

12.非循环单链表插入节点伪算法

算法:遍历;查找;清空;销毁;求长度;排序;

数据结构与算法笔记整理---1(郝兵)_第1张图片

插入节点:r = p->pNext; p->pNext = q;  q->pNext = r;

删除节点:p->pNext=p->pNext->pNext;(这样写容易造成内存泄漏)

 正确写法:

 r=p->pNext;

 p->pNext=p->pNext->pNext;

 free(r);

 

每个链表节点的数据类型该如何表示的问题

节点:每个节点至少包含两个部分(数据 和 指针),结构体的某个成员指向他本身了。



typedef struct Node
{
    int data;  //数据域
    struct Node *pNext;  //指针域
}NODE,*PNODE;

13.链表的创建和链表的遍历算法



#include 
#include 
#include 
typedef struct Node
{
    int i;
    struct Node* pNext;
}NODE,*PNODE;


PNODE creat_list(void);
void trval_list(PNODE pHead);


int main(void)
{
    PNODE pHead=NULL;
    
    pHead=creat_list();
    trval_list(pHead);
    
    
    return 0;
}

PNODE creat_list(void)     //创建链表
{
    int len;  //有效节点的个数
    int i;
    int val;  //用来临时存放用户输入节点的值
    
    PNODE pHead=(PNODE)malloc(sizeof(NODE));
    if(NULL==pHead)
    {
        printf("分配失败,程序终止!\n");
        exit(-1);
     }
    
     PNODE pLast=pHead;
     pLast->pNext=NULL;
    
    printf("请输入您需要的节点个数:len=");
    scanf("%d",&len);
    
    for(i=0;ii =val;
        pNew->pNext=NULL;
        pLast->pNext=pNew;
        pLast=pNew;
        
    }
    
    
    return pHead;
}
void trval_list(PNODE pHead)    // 遍历链表
{
    PNODE p=NULL;
    
    p=pHead->pNext;
    while(p!=NULL)
    {
        printf("%d\n",p->i);
        p=p->pNext;
        
     }
     return;    //不返回值,但是告诉别人这个已经结束了
}

14.通过链表的排序算法,讨论什么是算法,什么是范型

算法:
        狭义的算法:是与数据的存储方式密切相关的。
        广义的算法:与数据额存储方式无关
        范型:(要学习 C++中的模板与函数重载)
            利用某种技术达到的效果:
                                   不同的存储方式,执行的操作是一样的。(造成一种假象,让人感觉都是一样的)


重载:赋予一个事物不同的含义

排序函数:

void sort_list(PNODE pHead)
{
    int i, j, t;
    int len = length_list(pHead);
    PNODE p, q;
    
    for (i=0,p=pHead->pNext; ipNext)
    {
        for (j=i+1,q=p->pNext; jpNext)
        {
            if (p->data > q->data)  //类似于数组中的:  a[i] > a[j]
            {
                t = p->data;//类似于数组中的:  t = a[i];
                p->data = q->data; //类似于数组中的:  a[i] = a[j];
                q->data = t; //类似于数组中的:  a[j] = t;
            }
        }
    }

    return;
}

15.学习算法的一些感想

学习算法:有些东西想不出来,把答案的程序看懂。(流程  语句的功能   试数)

你可能感兴趣的:(数据结构与算法)