热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构笔记(郝斌主讲)(2015112622:12:54更新完毕)

教材-课外书籍推荐高一凡(伪算法→真代码)数据结构概述定义我们如何把现实生活中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上

教材-课外书籍推荐

高一凡(伪算法→真代码)

数据结构概述
 定义
  我们如何把现实生活中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应操作,这个相应的操作也叫算法

  数据结构 = 个体 + 个体的关系
  算法 = 对存储数据的操作

 算法
  解题的方法和步骤

  衡量算法的标准
   1.时间复杂度
    大概程序要执行的次数,而非执行的时间
   2.空间复杂度
    算法执行过程中大概所占用的最大内存
   3.难易程度

   4.健壮性

 数据结构的地位
  数据结构是软件中最核心的课程

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

 最后编辑于2015年8月18日23:10:06


 预备知识
  指针
   指针的重要性:
    指针是C语言的灵魂
   定义
    地址
     地址就是内存单元的编号
     从0开始的非负整数
     范围: 0--FFFFFFFF(0——4G-1)

    指针:
     指针就是地址,地址就是指针
     指针变量是存放内存单元地址的变量
     指针的本质是一个操作受限的非负整数

   分类:
    1.基本类型的指针

    2.指针和数组的关系

 最后编辑于2015年8月19日23:06:51

 结构体
  为什么会出现结构体
   为了表示一些复杂的数据,而普通的基本类型变量无法满足要求

  什么叫结构体
   结构体是用户根据实际需要自己定义的复合数据类型

  如何使用结构体
   两种方式
   struct Student  st = {1000, "zhangsan", 20};
 
   struct Student * pst;

   1.
    st.sid
   2.
    pst->sid
    pst所指向的结构体变量中的sid这个成员

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

跨函数使用内存---通过动态内存分配实现
 一般情况下,自定义函数结束后内存释放,唯有动态分配的内存在没有遇见free函数的情况下,自定义函数结束了,但内存仍然存在。

 最后编辑于2015年8月20日23:00:44

模块一:线性结构[把所有的结点用一根直线穿起来]
连续存储[数组]
1. 什么叫数组
元素类型相同,大小相同
2. 数组的优缺点


离散存储[链表]
定义:
n个结点离散分配
彼此通过指针相连
每个节点只有一个前驱节点,每个节点只有一个后续节点
首节点没有前驱结点,尾节点没有后续节点

专业术语:
首节点:
第一个有效节点
尾节点:
最后一个有效节点
头结点:
头结点是数据类型和首结点类型一样
第一个有效节点之前的那个节点
头结点并不存放有效数据
加头结点的目的主要是为了方便对链表的操作
头指针:
指向头结点的指针变量
尾指针:
指向尾节点的指针变量

如果希望通过一个函数对链表进行处理,我们至少需要接受链表的哪些信息:
只需要一个参数:头指针
因为我们通过头指针可以推算出链表的其他所有信息


分类:
单链表
双链表:
每一个节点有两个指针域

循环链表
能通过任何一个节点找到其他所有的结点
非循环链表
算法:
遍历
查找
清空
销毁
求长度
排序
删除节点
插入节点
算法:
狭义的算法是与数据的存储方式密切相关
广义的算法是与数据的存储方式无关
泛型:
利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的

链表排序算法

1 for(i=0,p=pHead->pNext; i1; ++i,p=p->pNext)
2 {
3 for(j=i+1,q=p->pNext; jpNext)
4 {
5 if(p->data > q->data)//类似于数组中的 a[i] > a[j]
6 {
7 t = p->data;//类似于数组中的:t = a[i];
8 p->data = q->data;//类似于数组中的:a[i] = a[j];
9 q->data = t;//类似于数组中的 a[j] = t;
10 }
11 }
12 }

再论数据结构
  狭义:
    数据结构是专门研究数据存储的问题
    数据的存储包含两方面:个体的存储 + 个体关系的存储
  广义:
    数据结构既包含数据的存储也包含数据的操作
    对存储数据的操作就是算法
算法:
  狭义
    算法是和数据的存储方式密切相关
  广义
    算法和数据的存储方式无关
    这就是泛型思想
数据的存储结构有几种
  线性
  连续存储【数组】
    优点
      存储速度很快
    缺点
      事先必须知道数组的长度
      插入删除元素很慢
      空间通常是有限制的
      需要大块连续的内存块
      插入删除的效率极低

  离散存储【链表】
   优点
    空间没有限制
    插入删除元素很快

   缺点
    存取速度很慢

线性结构的应用--栈

线性结构的应用--队列


非线性


链表的优缺点:

线性结构的两种常见应用之一 栈
定义
一种可以实现“先进后出”的存储结构
栈类似于箱子

分类
静态栈
动态栈

算法
出栈
压栈

应用


线性结构的两种常见应用之二 队列

 

定义:
一种可以实现“先进先出”的存储结构
分类:
链式队列 -- 用链表实现

静态队列 -- 用数组实现
静态队列通常都必须是循环队列

循环队列的讲解:
1.静态队列为什么必须是循环队列吧
2.循环队列需要几个参数来确定
需要2个参数来确定
front
rear


3.循环队列各个参数的含义
2个参数不同场合有不同的含义
建议初学者先记住,然后慢慢体会
1).队列初始化
font和rear的值都是零
2).队列非空
font代表的是队列的第一个元素
rear代表的是队列的有效元素的最后一个有效元素的下一个元素
3).队列空
font和rear的值相等,但不一定是零
4.循环队列入队伪算法讲解

两步完成:
1.将值存入r所代表的位置
2.错误的写法rear = rear + 1;
正确的写法是:rear = (rear + 1) % 数组的长度


5.循环队列出队伪算法讲解

front = (front+1) % 数组的长度
6.如何判断循环队列是否为空

如果front与rear的值相等,
则该队列就一定为空


7.如何判断循环队列是否已满

预备知识:
       front的值可能比rear大,
       front的值也可能比rear小,
       当然也可能两者相等
      两种方式
       1.多增加一个表标识参数
       2.少用一个元素[通常使用第二种方式]
       如果r和f的值紧挨着,则队列已满
       用C语言伪算法表示就是:
       if((r+1)%数组的长度==f)
        已满
       else
        不满

   不满
    队列算法
     入队
     出队
    队列的具体应用:
     所有时间和有关的操作都有队列的影子
 
专题:递归
 定义:
  一个函数自己直接或间接调用自己
 
  递归满足三个条件
   1.递归必须得有一个明确的终止条件
   2.该函数所处理的数据规模必须在递减
   3.这个转化必须是可解的
 
  循环和递归
   递归:
    易于理解
    速度慢
    存储空间大
   循环:
    不易理解
    速度快
    存储空间小
 
 举例:
 
 1. 求阶乘
 2.  1+2+3+4+……100的和
 3. 汉诺塔
 4. 走迷宫

递归的应用:
树和森林就是以递归的方式定义的
树和图的很多算法都是以递归来实现的
很多数学公式就是以递归的方式定义的
斐波那契序列
1 2 3 5 8 13 21 34
逻辑结构
线性
数组
链表
栈和队列是一种特殊的线性结构

非线性


物理结构


模块二:非线性结构

树定义
专业定义:
1.有且只有一个称为根的节点
2.有若干个互不相交的子树,这些子树本身也是一棵树
通俗的定义:
1.树是由节点和边组成
2.每个节点只有一个父节点但可以有多个子节点
3.但有一个节点例外,该节点没有父节点,此节点称为根节点
专业术语
节点 父节点 子节点
子孙 堂兄弟
深度:
从根节点到最底层节点的层数称之为深度
根节点是第一层
叶子节点:
没有子节点的节点
非终端节点
实际就是非叶子节点

子节点的个数称为度

树分类
一般树
任意一个节点的子节点的个数都不受限制
二叉树
任意一个节点的子节点个数最多两个,且子节点的位置不可更改

分类:
一般二叉树
满二叉树
在不增加树的层数的前提下,无法再多添加一个节点的二叉树就是满二叉树

完全二叉树
如果只是删除了满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全二叉树

森林
n个互不相交的树的集合

树的存储
二叉树的存储
连续存储[完全二叉树]
优点:
查找某个节点的父节点和子节点(也包括判断有没有子节点)速度很快
缺点:
耗用内存空间过大

链式存储


一般树的存储
双亲表示法
求父节点方便
孩子表示法
求子节点方便
双亲孩子表示法
求父节点和子节点都很方便
二叉树表示法
把一个普通树转化成二叉树来存储
具体转换方法:
设法保证任意一个节点的
左指针域指向它的第一个孩子
右指针域指向它的兄弟
只要能满足此条件,就可以把一个普通树转化为二叉树
一个普通树转化成的二叉树一定没有右子树

森林的存储

  先把森林转化为二叉树,再存储二叉树

 

操作

 

        遍历

 

            先序遍历

 

                先访问根节点

 

                再先序访问左子树

 

                再先序访问右子树

 


 

 

中序遍历[中间访问根节点]

 

                中序遍历左子树

 

                再访问根节点

 

                再中序遍历右子树
后序遍历[最后访问根节点]
                先中序遍历左子树
                再中序遍历右子树
                再访问根节点

 

 

        已知两种遍历序列求原始二叉树
            通过先序和中序    或者    中序和后序我们可以
            还原出原始的二叉树
            但是通过先序和后序是无法还原出原始的二叉树的
 
已知先序和中序
已知中序和后序

            换种说法:
                只有通过先序和中序,    或通过中序和后序
                我们才可以唯一的确定一个二叉树
链式二叉树简单实现
如图,用程序编写前序遍历,中序遍历,后序遍历
代码如下

1 #include
2 #include<malloc.h>
3
4 struct BTNode
5 {
6 char data;
7 struct BTNode * pLchild; //p是指针&#xff0c;L是左&#xff0c; child是孩子
8 struct BTNode *pRchild;
9 };
10
11 struct BTNode * CreateBTree();
12 void PreTraverseBTree(struct BTNode * pT);
13 void InTraverseBTree(struct BTNode * pT);
14 void PostTraverseBTree(struct BTNode * pT);
15
16 int main(void)
17 {
18 struct BTNode * pT &#61; CreateBTree();
19
20 printf("前序遍历:\n");
21 PreTraverseBTree(pT);//前序遍历
22 printf("中序遍历:\n");
23 InTraverseBTree(pT);//中序遍历
24 printf("后序遍历:\n");
25 PostTraverseBTree(pT);//后序遍历
26
27 return 0;
28 }
29
30 void PostTraverseBTree(struct BTNode * pT)
31 {
32 if(pT !&#61; NULL)
33 {
34
35 if(pT->pLchild !&#61; NULL)
36 {
37 PostTraverseBTree(pT->pLchild);
38 }
39
40 if(pT->pRchild !&#61; NULL)
41 {
42 PostTraverseBTree(pT->pRchild);
43 }
44
45 printf("%c\n",pT->data);
46
47 //pT->pLchild可以代表整个左子树
48 }
49
50
51 /*
52 ·伪算法
53 先访问根节点
54 再先序访问左子树(先序即前序?);
55 再先序访问右子树
56 */
57 }
58
59
60 void InTraverseBTree(struct BTNode * pT)
61 {
62 if(pT !&#61; NULL)
63 {
64
65 if(pT->pLchild !&#61; NULL)
66 {
67 InTraverseBTree(pT->pLchild);
68 }
69
70 printf("%c\n",pT->data);
71
72 if(pT->pRchild !&#61; NULL)
73 {
74 InTraverseBTree(pT->pRchild);
75 }
76
77 //pT->pLchild可以代表整个左子树
78 }
79
80
81 /*
82 ·伪算法
83 先访问根节点
84 再先序访问左子树(先序即前序?);
85 再先序访问右子树
86 */
87 }
88
89
90 void PreTraverseBTree(struct BTNode * pT)
91 {
92 if(pT !&#61; NULL)
93 {
94 printf("%c\n",pT->data);
95 if(pT->pLchild !&#61; NULL)
96 {
97 PreTraverseBTree(pT->pLchild);
98 }
99 if(pT->pRchild !&#61; NULL)
100 {
101 PreTraverseBTree(pT->pRchild);
102 }
103
104 //pT->pLchild可以代表整个左子树
105 }
106
107
108 /*
109 ·伪算法
110 先访问根节点
111 再先序访问左子树(先序即前序?);
112 再先序访问右子树
113 */
114 }
115
116 struct BTNode * CreateBTree()//功能弱&#xff0c;只是静态的
117 {
118 struct BTNode * pA &#61; (struct BTNode *)malloc(sizeof(struct BTNode));
119 struct BTNode * pB &#61; (struct BTNode *)malloc(sizeof(struct BTNode));
120 struct BTNode * pC &#61; (struct BTNode *)malloc(sizeof(struct BTNode));
121 struct BTNode * pD &#61; (struct BTNode *)malloc(sizeof(struct BTNode));
122 struct BTNode * pE &#61; (struct BTNode *)malloc(sizeof(struct BTNode));
123
124 pA->data &#61; &#39;A&#39;;
125 pB->data &#61; &#39;B&#39;;
126 pC->data &#61; &#39;C&#39;;
127 pD->data &#61; &#39;D&#39;;
128 pE->data &#61; &#39;E&#39;;
129
130 pA->pLchild &#61; pB;
131 pA->pRchild &#61; pC;
132 pB->pLchild &#61; pB->pRchild &#61; NULL;
133 pC->pLchild &#61; pD;
134 pC->pRchild &#61; NULL;
135 pD->pLchild &#61; NULL;
136 pD->pRchild &#61; pE;
137 pE->pLchild &#61; pE->pRchild &#61; NULL;
138
139 return pA;
140 }
141

 

//运行如下
快速排序

转:https://www.cnblogs.com/huangtao1996/p/4747544.html



推荐阅读
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 在IDEA中运行CAS服务器的配置方法
    本文介绍了在IDEA中运行CAS服务器的配置方法,包括下载CAS模板Overlay Template、解压并添加项目、配置tomcat、运行CAS服务器等步骤。通过本文的指导,读者可以轻松在IDEA中进行CAS服务器的运行和配置。 ... [详细]
author-avatar
曉--伍_621
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有