计算机专业基础 -- 数据结构入门与算法基础知识
目录
2-3查找树
红黑树
排序算法
基本算法思想
编程基础
2-3查找树
2-结点:含有一个键(及值)和两条链接,左链接指向的2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。
3-结点:含有两个键(及值)和三条链接,左链接指向的2-3树中的键都小于该结点,中链接指向的2-3树中的键都位于该结点的两个键之间,右链接指向的2-3树中的键都大于该结点。
2-3指的是2叉-3叉的意思,一颗完美平衡的2-3查找树中的所有空链接到根结点的距离都是相同的。
查找:要判断一个键是否在树中,我们先将它和根结点中的键比较。如果它和其中的任何一个相等,查找命中。否则我们就根据比较的结果找到指向相应区间的链接,并在其指向的子树中递归地继续查找。如果这是个空链接,查找未命中。
插入:要在2-3树中插入一个新结点,我们可以和二叉查找树一样先进行一次未命中的查找,然后把新结点挂在树的底部。但这样的话树无法保持完美平衡性。我们使用2-3树的主要原因就在于它能够在插入之后继续保持平衡。如果未命中的查找结束于一个2-结点,我们只要把这个2-结点替换为一个3-结点,将要插入的键保存在其中即可。如果未命中的查找结束于一个3-结点,事情就要麻烦一些。
1、只有一个3-结点的树,向其插入一个新键。这棵树唯一的结点中已经没有可插入的空间了。我们又不能把新键插在其空结点上(破坏了完美平衡)。为了将新键插入,我们先临时将新键存入该结点中,使之成为一个4-结点。创建一个4-结点很方便,因为很容易将它转换为一颗由3个2-结点组成的2-3树(如图所示),这棵树既是一颗含有3个结点的二叉查找树,同时也是一颗完美平衡的2-3树,其中所有空链接到根结点的距离都相等。
2、向一个父结点为2-结点的3-结点中插入新键。假设未命中的查找结束于一个3-结点,而它的父结点是一个2-结点。在这种情况下我们需要在维持树的完美平衡的前提下为新键腾出空间。我们先像刚才一样构造一个临时的4-结点并将其分解,但此时我们不会为中键创建一个新结点,而是将其移动至原来的父结点中。(如图所示)
3、向一个父结点为3-结点的3-结点中插入新键。假设未命中的查找结束于一个3-结点,而它的父结点是一个3-结点。我们再次和刚才一样构造一个临时的4-结点并分解它,然后将它的中键插入它的父结点中。但父结点也是一个3-结点,因此我们再用这个中键构造一个新的临时4-结点,然后在这个结点上进行相同的变换,即分解这个父结点并将它的中键插入到它的父结点中去。我们就这样一直向上不断分解临时的4-结点并将中键插入更高的父结点,直至遇到一个2-结点并将它替换为一个不需要继续分解的3-结点,或者是到达3-结点的根。
总结:先找插入结点,若结点有空(即2-结点),则直接插入。如结点没空(即3-结点),则插入使其临时容纳这个元素,然后分裂此结点,把中间元素移到其父结点中。对父结点亦如此处理。(中键一直往上移,直到找到空位,在此过程中没有空位就先搞个临时的,再分裂。)
2-3树插入算法的根本在于这些变换都是局部的:除了相关的结点和链接之外不必修改或者检查树的其他部分。每次变换中,变更的链接数量不会超过一个很小的常数。所有局部变换都不会影响整棵树的有序性和平衡性。
构造:和标准的二叉查找树由上向下生长不同,2-3树的生长是由下向上的(因为插入节点时是往上挤)。
优点:2-3树在最坏情况下仍有较好的性能。每个操作中处理每个结点的时间都不会超过一个很小的常数,且这两个操作都只会访问一条路径上的结点,所以任何查找或者插入的成本都肯定不会超过对数级别。完美平衡的2-3树要平展的多。例如,含有10亿个结点的一颗2-3树的高度仅在19到30之间。我们最多只需要访问30个结点就能在10亿个键中进行任意查找和插入操作。
缺点:我们需要维护两种不同类型的结点,查找和插入操作的实现需要大量的代码,而且它们所产生的额外开销可能会使算法比标准的二叉查找树更慢。平衡一棵树的初衷是为了消除最坏情况,但我们希望这种保障所需的代码能够越少越好。
红黑树
红黑树就是用红链接表示3-结点的2-3树,是对2-3查找树的改进,它能用一种统一的方式完成所有变换,背后的思想是用标准的二叉查找树(完全由2-结点构成)和一些额外的信息(替换3-结点)来表示2-3树。
那么红黑树的插入、构造就可转化为2-3树的问题,即:在脑中用2-3树来操作,得到结果,再把结果中的3-结点转化为红链接即可。而2-3树的插入:有空则插,没空硬插,再分裂(类似堆排序的先放在堆底再调整)。
我们将树中的链接分为两种类型:红链接将两个2-结点连接起来构成一个3-结点,黑链接则是2-3树中的普通链接。确切地说,我们将3-结点表示为由一条左斜的红色链接相连的两个2-结点。因为每个结点都只会有一条指向自己的链接(从它的父结点指向它),我们将链接的颜色保存在表示结点的Node数据类型的布尔变量color中(若指向它的链接是红色的,那么该变量为true,黑色则为false)。当我们提到一个结点颜色时,我们指的是指向该结点的链接的颜色。
这种表示法的一个优点是,我们无需修改就可以直接使用标准二叉查找树的get()方法。对于任意的2-3树,只要对结点进行转换,我们都可以立即派生出一颗对应的二叉查找树。我们将用这种方式表示2-3树的二叉查找树称为红黑树。
排序算法
/** * 冒泡排序* 比较相邻的元素。如果第一个比第二个大,就交换他们两个。* 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。* 针对所有的元素重复以上的步骤,除了最后一个。* 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。*/
public static void bubbleSort(int[] numbers) { int temp; // 记录临时中间值 int size = numbers.length; // 数组大小 for (int i = 0; i < size - 1; i++)for (int j = i + 1; j < size; j++)if (numbers[i] < numbers[j]) { // 交换两数的位置 temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; }
}
/** * 快速排序* 从数列中挑出一个元素,称为“基准”* 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后, * 该基准是它的最后位置。这个称为分割(partition)操作。* 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。*/ public static void quickSort(int[] numbers, int start, int end) { if (start < end) { int base = numbers[start]; // 选定的基准值(第一个数值作为基准值) int temp; // 记录临时中间值 int i = start, j = end; do { while ((numbers[i] < base) && (i < end)) i++; while ((numbers[j] > base) && (j > start)) j--; if (i <= j) { temp = numbers[i]; numbers[i] = numbers[j]; numbers[j] = temp; i++; j--; } } while (i <= j); if (start < j) quickSort(numbers, start, j); if (end > i) quickSort(numbers, i, end); }
}
/** * 选择排序* 在未排序序列中找到最小元素,存放到排序序列的起始位置* 再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。* 以此类推,直到所有元素均排序完毕。*/
public static void selectSort(int[] numbers) { int size = numbers.length, temp; for (int i = 0; i < size; i++) { int k = i; for (int j = size - 1; j >i; j--) if (numbers[j] < numbers[k]) k = j; temp = numbers[i]; numbers[i] = numbers[k]; numbers[k] = temp; }
}
/** * 插入排序* 从第一个元素开始,该元素可以认为已经被排序* 取出下一个元素,在已经排序的元素序列中从后向前扫描* 如果该元素(已排序)大于新元素,将该元素移到下一位置* 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置* 将新元素插入到该位置中* 重复步骤2*/
public static void insertSort(int[] numbers) { int size = numbers.length, temp, j; for(int i=1; i<size; i++) { temp = numbers[i]; for(j = i; j > 0 && temp < numbers[j-1]; j--) numbers[j] = numbers[j-1]; numbers[j] = temp; }
}
/** * 归并排序* 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列* 设定两个指针,最初位置分别为两个已经排序序列的起始位置* 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置* 重复步骤3直到某一指针达到序列尾* 将另一序列剩下的所有元素直接复制到合并序列尾*/
public static void mergeSort(int[] numbers, int left, int right) { int t = 1;// 每组元素个数 int size = right - left + 1; while (t < size) { int s = t;// 本次循环每组元素个数 t = 2 * s; int i = left; while (i + (t - 1) < size) { merge(numbers, i, i + (s - 1), i + (t - 1)); i += t; } if (i + (s - 1) < right) merge(numbers, i, i + (s - 1), right); }
}
private static void merge(int[] data, int p, int q, int r) { //归并算法int[] B = new int[data.length]; int s = p; int t = q + 1; int k = p; while (s <= q && t <= r) { if (data[s] <= data[t]) { B[k] = data[s]; s++; } else { B[k] = data[t]; t++; } k++; }if (s == q + 1) B[k++] = data[t++]; else B[k++] = data[s++]; for (int i = p; i <= r; i++) data[i] = B[i];
}
基本算法思想
迭代法:又称辗转法,是一种不断用变量的旧值递推新值的过程。分为精确迭代(杨辉三角、内在移动算法等)和近似迭代(二分法和牛顿迭代法等)。
蛮力法:又叫穷举,应用于图的搜索等各种遍历。
分治法:把一个较大的问题分解成几个与原问题相似的子问题,找到求出这几个子问题的解法后,再以适当的方法组织,把它们合成求整个问题的解法。(1) 分解:将要解决的问题划分成若干规模较小的同类问题;(2) 求解:当子问题划分得足够小时,用较简单的方法解决;(3) 合并:按原问题的要求,将子问题的解逐层合并构成原问题的解。
贪心法:适用于能够由局部最优达到全局最优的优化问题;多步判断过程,最终的判断序列对应于问题的最优解;每一步的判断都是一个当前最优的抉择,这个抉择计算设计的好坏,决定了算法的成败;需要对具体的贪心算法的正确性进行必要的证明。近似贪心问题:找零问题。
动态规划:将待求解问题分解成若干个子问题,分阶段求解子问题,前一阶段子问题的解成为求后续阶段子问题的解的计算信息,最后用这些子问题的最优解构造出原问题的最优解。适合用动态规划求解的问题的特征:子问题重叠性(子问题重复、子问题的解在下一阶段决策中,延续子问题多次使用);最优子结构(一个问题的最优解包含着它的子问题的最优解)。如背包问题、投资分配、最长子段和。
概率算法:对产生随机数的数学方法要求:(1)产生的数列具有均匀总体随机样本的统计学性质;(2)产生的数列要有足够的周期;(3)产生数列要速度快,占用计算机内存少。蒙特卡罗算法、舍伍德算法、拉斯维加斯算法、n皇后问题、 线性同余发生器(Linear Congruence Generator, LCG)。
编程基础
结构体调用: (*指针变量名称).成员名称 指针变量名称->成员名称
b = a-b; //不设置辅助变量交换a和b的值
a = a-b;
b = a+b;
计算机专业基础 -- 数据结构入门与算法基础知识相关推荐
- 计算机队列概念,2020计算机专业考研数据结构知识点:栈、队列和数组
2020计算机专业考研数据结构知识点:栈.队列和数组 1.栈.队列的定义及其相关数据结构的概念,包括:顺序栈.链栈.循环队列.链队列等.栈与队列存取数据(请注意包括:存和取两部分)的特点. 2. 掌握 ...
- sql数据库教程百度云_【推荐】零基础水彩画入门教程|零基础水彩教程百度云...
零基础水彩画入门教程|零基础水彩教程百度云! 照着教程画却总是画不好,这些水彩技法你真的学会了吗? 盲目地照着葫芦画瓢,不懂控制确实很难学会,可以关注一下公众号:每日学绘画,可以领取水彩电子书和全套视 ...
- 学计算机做人需要有什么基础,计算机专业学生装逼入门
前一段看过几篇讨论"IT从业者应该怎样装逼"的文章.我窃以为那些文章中,技巧成分过重,而装逼这事应以修炼内功为主.这一修炼需要长期努力,至少应该从在研究生时期(甚至本科生时期)就修 ...
- 学计算机做人需要有什么基础,计算机专业学生装逼入门(文/郭策)
前一段看过几篇讨论"IT从业者应该怎样装逼"的文章.我窃以为那些文章中,技巧成分过重,而装逼这事应以修炼内功为主.这一修炼需要长期努力,至少应该从在研究生时期(甚至本科生时期)就修 ...
- 计算机专业考研数据结构比较,计算机专业考研科目:数据结构重点汇总
今天说说文都考研网小编为同学们整理了数据结构科目的重点知识点,供大家参考复习. 1.数据结构的基本概念.基本原理和基本方法,能够对算法进行基本的时间复杂度和空间复杂度的分析;能够运用数据结构的基本原理 ...
- 计算机专业的校本教材,计算机应用基础校本教材编写研究
校本课程(school-basedcurriculum)即以学校为本位.由学校自己确定的课程,与国家课程.地方课程相对应.这一思想源于20世纪六七十年代的西方发达国家,主张学校的教师.学生.学生家长. ...
- C语言数据结构-程序设计与算法基础II-电大同步进度
第一讲-数据结构基础概念 https://blog.csdn.net/aiqq136/article/details/115209556 第二章线性表 https://blog.csdn.net/ai ...
- python语言入门w-Python算法基础
有穷性:算法的有穷性是指算法必须能在执行有限个步骤之后终止: 确切性:算法的每一步骤必须有确切的定义: 输入项:一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条 ...
- 江西旅游商贸职业学院计算机题目,2019年江西旅游商贸职业学院发布单独招生计算机专业实操考试方案Windows基础部分、IE基础(50分)...
Windows基础部分.IE基础(50分) 文件管理概念区分文件和文件夹的区别:文件夹包含文件文件属性只读.隐藏:选中.右击.属性文件类型常用文件的类型:Word(*.doc).文本文档(*.txt) ...
- 数据结构(二)之算法基础
一.为什么要学习算法? 先来个简单的算法比较:求sum=1+2+3+...+(n-1)+n的结果. 输入整数n,输出 sum 解法一:for循环 function sum(n){var s=0; // ...
最新文章
- 你了解计算机系统的层次结构吗?计算机语言怎么发展的?
- java传值到sql decode语句_SQL之DECODE
- LeetCode-best time to buy and sell stock 2 数组
- nginx源码学习资源
- C++ primer第六章6.4函数的学习 之函数的重载
- 说说说vue.js中的组
- java setundecorated_java JFrame中与setUndecorated()相关的几个特效
- AndroidStudio_使用NanoHTTPD搭建HTTP服务_把android设置当成一个http服务器来使用---Android原生开发工作笔记225
- LFS6.3安装全过程(一)
- 一个线上SQL死锁异常分析:深入了解事务和锁
- VB代码VB小程序:实现USB摄像头视频图像的监控、截图、录像
- 蘑菇街直播实战技巧带你解决直播开发难题
- 中国土壤修复行业十四五专项调研及投资战略规划报告2022-2027年新版
- 干细胞相关研究最新进展(2021年9月)
- 计算机考研除了专业课还要学什么时候,计算机考研专业课什么时候开始看
- 【推荐】泰坦尼克号乘客生存分析——用机器学习告诉你,如果你在当时的船上,有多大机率生还?
- 一句平静而感人的英文电影对白
- 重磅!2020 ACM杰出科学家名单出炉:叶杰平、崔鹏等26位华人学者上榜
- 命令行 笔记本键盘禁用_如何在 Ubuntu 20.04 上禁用坞站(dock) | Linux 中国
- 黑客摆弄技术 攻击政府部门网站
热门文章
- Spoj REPEATS 后缀自动机+set
- 14.6.4 Configuring the Memory Allocator for InnoDB 配置InnoDB 内存分配器
- 模拟猜数(POJ2328)
- 算法和数据结构---排序---插入排序
- 微软软件开发技术二十年回顾(MFC篇)
- 明天开始放假了[2.5-2.13],春节期间计划
- 【Git/Github学习笔记】Git分支使用场景和标签管理、总结
- 【Matlab学习笔记】【图像滤波去噪】高斯平滑滤波
- 模板题——图论相关(1)
- 批量修改txt文件名,删除相同部分