![](https://img-blog.csdnimg.cn/20201014180756780.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
数据结构与算法
冯志佳
这个作者很懒,什么都没留下…
展开
-
基数排序(桶排序)
基数排序(俗称桶排序):基数排序是一种全新的排序思想,不同于之前学的几种排序.之前学的 直接插入排序O(n^2)、希尔排序O(n^1.3 - O^2)、 冒泡排序O(n^2)、简单选择排序O(n^2)、快速排序O(nlogn)、堆排序O(nlogn)、 归并排序O(nlogn)这些排序都是基于交换元素的排序思想,只不过有的排序算法交换的是相邻元素、有的排序算法交换的是不相邻的元素。 结论是 交换不相邻元素的排序算法要比交换相邻元素的排序算法要高效。基数排序是根据多关键字 按主次实行"分配"、"收.原创 2021-08-31 19:34:02 · 393 阅读 · 0 评论 -
归并排序算法
归并排序(MergeSort) : 这里我们采用的是二路归并 思想:将两个有序数组合并成一个有序数组的过程。 时间复杂度:O(nlogn) 空间复杂度O(n) 稳定性 : 归并排序是稳定的排序算法 归并排序的时间复杂度和空间复杂度分析 归并排序递归到最后本质上就是一棵倒着的满二叉树。 每一趟归并的时间复杂度最坏是O(n),因为n个元素,最多比较n-1次就可完全确定顺序,所以时间复杂度最坏是O(n) 而满二...原创 2021-08-30 14:52:04 · 468 阅读 · 0 评论 -
堆的相关操作
堆: 堆本质上就是一棵用数组存储的完全二叉树。 因此用数组存储的完全二叉树的性质,堆也具备。 性质1: 对于i结点 他的左孩子是2i 他的右孩子是2i+1 性质2: 如果 2i < n ,则代表该结点没有左孩子 性质3: 如果 2i+1 < n , 则代表该结点没有右孩子 性质4: 1<=i<=n/2 i所指结点均为分支结点。 性质5: 当i>n/2时 i所指结点是叶子结点。 堆还具备自...原创 2021-08-27 16:06:02 · 229 阅读 · 0 评论 -
简单选择排序
简单选择排序: 空间复杂度O(1) 时间复杂度O(n^2) 不稳定的排序算法 2 2 1 此序列使用简单选择排序 是 1 2 2 最后的这个2是第一个2. 简单选择排序算法又叫做众生平等算法: 无论数组是何种顺序、 有序、基本有序、还是无序。 时间复杂度都是O(n^2) 简单选择排序既可以对数组排序,又可以对链表排序(交换结点、交换结点里面的值都可)。代码展示:#include<stdio...原创 2021-08-26 16:15:43 · 129 阅读 · 0 评论 -
快速排序(分治思想)
快速排序: 空间复杂度 :O(logn)-O(n) 时间复杂度 :O(nlogn)-O(n^2) 稳定性: 快速排序是不稳定的排序算法 2 2 1 排完之后相对顺序发生了变化 只适用于数组排序。前面提到的 直接插入排序、冒泡排序、希尔排序、在元素有序或者说基本有序的情况下,时间复杂度为O(n).而快速排序跟其他的几种排序算法恰恰相反, 快速排序在元素有序或者逆序的情况下,时间复杂度最糟糕为O(n^2).而在元素随机、或者说找的元素接近基准元素...原创 2021-08-26 11:13:47 · 6574 阅读 · 0 评论 -
冒泡排序算法
冒泡排序: 每次排序都将待排序列中最大的元素移至数组末尾。 空间复杂度O(1) 时间复杂度O(n^2) 冒泡算法具有稳定性。 冒泡排序算法即适用于数组又适用于链表。代码展示:#include<stdio.h>#include<stdlib.h>#define null NULL /* 冒泡排序: 每次排序都将待排序列中最大的元素移至数组末尾。 空间复杂度O(1) 时间复杂度O...原创 2021-08-24 15:29:47 · 345 阅读 · 0 评论 -
希尔排序(Shell Sort)
都说希尔排序是执行多次的直接插入排序,最后增量d都会为1,执行一次针对全数组的直接插入排序。那难免会有疑问,直接插入排序时间复杂度是O(n^2),希尔还是执行多次的插入排序,那给人的感觉应该是执行的更慢,而不是更快啊。直到我看到了这个回答:为啥希尔能突破O(N^2)的界,可以用逆序数来理解,假设我们要从小到大排序,一个数组中取两个元素如果前面比后面大,则为一个逆序,容易看出排序的本质就是消除逆序数,可以证明对于随机数组,逆序数是O(N^2)的,而如果采用“交换相邻元素”的办法来消除逆序,每次正好只消原创 2021-08-24 10:20:04 · 199 阅读 · 0 评论 -
直接插入排序算法
这个一定要认真学习,把每种查找算法尽可能的都实现一遍,(除了AVL树、 红黑树)。每种查找算法的特点都要熟练于心。原创 2021-08-23 15:40:20 · 259 阅读 · 0 评论 -
基础查找算法
把每种排序算法的特点,实现思路代码都敲一遍,熟练于心。发原创 2021-08-20 10:39:39 · 95 阅读 · 0 评论 -
霍夫曼树以及霍夫曼编码(动态数组实现方式)
霍夫曼编码是用于数据压缩存储的。根据的原理是:任一个字符编码绝对不是另一个字符编码的前缀,并且出现次数最多的字符,所用编码的位数最小。以此来达到数据压缩的目的。霍夫曼树有两种实现方式:一种是基于链表的实现方式,另一种是基于动态数组的实现方式。本文是基于动态数组的实现方式:代码及结果展示:#include<stdio.h>#include<stdlib.h>#include<string.h>#define null NULL/* 哈夫曼树的构建原创 2021-08-12 19:27:42 · 859 阅读 · 0 评论 -
二叉排序树(基本操作)
二叉排序树的基本操作: 1、查找 2、增加 3、删除。代码展示及结果截图:#include<stdio.h>#include<stdlib.h>/* 二叉排序树 <==> 二叉搜索树 (BST) <==> 二叉查找树 1. 二叉排序树的查找功能 (递归、非递归实现) --> 查找效率很大程度上取决于二叉排序树的高度。 2. 二叉排序树的插入功能 (默认不同元素的值才插入) --> 先查找再插入 ...原创 2021-08-09 15:58:58 · 1942 阅读 · 0 评论 -
树的存储(孩子表示法)
找孩子元素相当方便,遍历某个元素数组后面的链表,即可获得该结点的所有孩子元素。但是找父亲元素麻烦点,需要遍历整个数组,而且每个数组的每个链表都需要遍历。时间复杂度就上去了。删除元素需要递归删除(别忘了free掉链表结点占用的存储空间),删除之后直接data域直接置为' ',child指针域直接置为null.没有采用那种删除掉一个元素之后数组中最后一个数据前移的操作。因为 数组中的相对顺序还是挺重要的,就怕那种有孩子的元素,孩子元素移动了位置,自己还不知道,导致父元素访问子元素的内容出问题。递归删原创 2021-08-05 09:22:23 · 2364 阅读 · 0 评论 -
树的存储(双亲表示法)
此种方式找父节点好找,但是找子结点需要遍历整个数组。删除某一个结点时:(思路) 1.该结点没有孩子,直接删除即可。 2.该结点有孩子,需要递归将孩子结点删除,然后再删除该结点。删除时的小细节: 1.每删除一个元素时,将数组中的最后一个元素前移,节省存储空间,遍历数组时方便,遍历的元素少,但是存在问题。(F结点有子结点,F的子结点在未删除的情况,F结点进行了移动,导致F结点的下标发生了变化,继而导致 GHK与F结点失联。) 2.删...原创 2021-08-04 10:36:44 · 3357 阅读 · 0 评论 -
二叉树基本操作以及二叉树线索化操作(C++ 版)
线索化的二叉树为:二叉树线索化的目的:1.二叉树的线索化的目的是为了快速找到遍历顺序中某个结点的前驱或者后继。2.二叉树线索化可以实现从某个结点开始遍历二叉树,而不用局限于只能从头结点进行遍历 3.所以二叉树的线索化与遍历序列有关,因为二叉树的遍历序列有三种,所以二叉树的线索化也有三种a.二叉树的先序线索化 b.二叉树的中序线索化 c. 二叉树的后序线索化4.二叉树的线索化说白了就是把那n+1个空指针利用起来,指向其前...原创 2021-07-20 14:53:51 · 725 阅读 · 0 评论 -
朴素匹配算法(BruteForce算法)
字符串的朴素匹配算法: (BruteForce 暴力匹配算法) 从主串头开始,依次选取和模拟串等长的子串,挨个字符匹配,如果匹配失败,立马检索下一个子串。 假设主串长为n 模拟串长为m 朴素匹配算法匹配成功的最好的时间复杂度为O(m) 匹配失败的最好的时间复杂度为O(n-m+1)~O(n) 匹配成功的最坏的时间复杂度为O(n-m+1)*m~O(nm) 匹配失败...原创 2021-07-14 14:56:34 · 3005 阅读 · 0 评论 -
串的静态数组实现方式(C++版)
串的基本操作有: StrAssign(&T,chars):赋值操作,把串T赋值为chars StrCopy(&T,S):复制操作,由串S复制得到串T StrEmpty(S):字符串的判空操作,若S为空串则返回True,否则返回false StrLength(S):求串长,返回串S的元素个数。 ClearString(&S):清空操作,将S清为空串。 DestoryString(&S):销毁串,将串S销毁(回收存储...原创 2021-07-14 11:13:06 · 776 阅读 · 0 评论 -
稀疏矩阵的存储与获取(十字链表法 C++版)
此稀疏矩阵我们打算采用十字链表法进行存储。代码实现及结果测试:#include<stdio.h>#include<stdlib.h>#define null NULL #define N 4 //矩阵的行数 #define M 7 //矩阵的列数 /* 稀疏矩阵的十字链表法实现方式 *///十字链表的元素结点typedef struct OLNode{ int i,j,value; //i行标 j列标 value元素值 struc...原创 2021-07-13 11:08:33 · 1296 阅读 · 0 评论 -
稀疏矩阵的存储与获取(行逻辑链接顺序表 C++版)
行逻辑链接顺序表实现稀疏矩阵的存储和获取。行逻辑链接顺序表其实就是一个加强版的三元组顺序表,在三元组顺序表的基础之上改善了提取数据的效率。它只不过是增加了一个数组,用来记录每行的非零元素在一维数组中的位置。这样,当我们获取某行的某个元素时,不必再把矩阵的非零元素整个都遍历一遍,而是只遍历与该行相关的非零元素。时间复杂度较三元组顺序表大大降低。但是多了一个数组的存储空间的开销。代码实现及结果测试:#include<stdio.h>#include<stdli...原创 2021-07-12 17:32:08 · 538 阅读 · 0 评论 -
稀疏矩阵的存储和获取(三元组顺序表存储方式 C++版)
稀疏矩阵如图所示,4行7列的矩阵一共28个元素,但是非零元素仅仅有5个。为了节省存储空间,实际上我们只需要存储这5个元素即可。稀疏矩阵的存储一共有三种方式: 1.三元组顺序表方式存储。 2.行逻辑链接的顺序表。 3.十字链表法。这篇是三元组顺序表方式存储的代码实现。代码实现以及测试结果:#include<stdio.h>#include<stdlib.h>/* 稀疏矩阵的三元组顺序表存储方式*/ ...原创 2021-07-12 15:41:42 · 2328 阅读 · 2 评论 -
三对角矩阵的存储和获取(C++版)
三对角矩阵如上图,红框部分是我们在数组中存储的部分。三对角的特点:|行标i-列标j|<=1的位置上才会有非零元素。其余位置都是0元素三对角矩阵矩阵下标和数组下标的映射关系是: 2*i+j-3代码实现及结果测试:#include<stdio.h>#include<stdlib.h> #define N 6 //N为对称矩阵的阶数 /* 三对角矩阵需要的数组大小是 3*N-2 三对角矩阵的特点: |行标i-列标j|<=...原创 2021-07-10 20:31:07 · 2130 阅读 · 0 评论 -
三角矩阵的存储和获取(C++版)
下三角矩阵如图, 三角形区域首先被存储,框型区域最后被存储于数组的最后一个元素中。代码及测试结果:#include<stdio.h>#include<stdlib.h>#define N 4 //N为三角矩阵的阶数//先把矩阵的下三角区元素存了void storageLowerTriangle(int array[] , int i, int j , int e){ array[i*(i-1)/2+j-1] = e;}//再存储常数Cvoi...原创 2021-07-10 19:52:30 · 1369 阅读 · 0 评论 -
对称矩阵的存储和获取(C++版)
对称矩阵如上图, 红色三角区域就是我们要存储的区域。我们采用的存储方式是按行存储。采用的存储方式不同,定位元素时的公式会不同。代码实现以及测试结果:#include<stdio.h>#include<stdlib.h> #define N 4 //N为对称矩阵的阶数 //对称矩阵元素的存储 array是要存储对称矩阵的数组 i,j是矩阵的下标(默认从a11开始),元素e是对称矩阵要存储的元素。 void storageValue(int a..原创 2021-07-10 18:56:31 · 1082 阅读 · 0 评论 -
中缀表达式转后缀表达式(C++版)
机算思想:1.初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。2.从左往后处理各个元素,直到末尾。 a.如果遇到操作数.直接加入后缀表达式。 b.如果遇到“(”直接入栈,如果遇到“)”,则依次弹出栈内运算符并加入后缀表达式.直到弹出“(”。注意“(”不加入后缀表达式。 c.遇到运算符,依次弹出栈中优先级高于或等于当前运算符的所有运算符。并加入后缀表达式,遇到"("或栈空则停止。之后再把当前运算符入栈。3.按上述方式处理完所有字符后,将栈...原创 2021-07-09 17:09:28 · 1373 阅读 · 0 评论 -
栈的括号匹配问题代码(C++版)
代码:bool bracketCheck(char str[], int length,SqStack &stack){ for(int i = 0; i < length; i++){ //左括号全部入栈 if( str[i] == '(' || str[i] == '[' || str[i] == '{' ){ Push(stack,str[i]); }else{ //扫描到右括号,且当前栈空 if(isEmpty(stack))原创 2021-07-07 18:34:58 · 1075 阅读 · 0 评论 -
队列的链表实现方式(C++版)
队列基于链表有两种实现方式:一种是带头结点的实现方式,一种是不带头结点的实现方式。带头结点的实现方式:基础代码:#include<stdio.h>#include<stdlib.h>#define ElemType int #define null NULL typedef struct LNode{ //链表结点 ElemType data; struct LNode *next; }LNode;typedef struct QNod原创 2021-07-06 22:07:37 · 1348 阅读 · 0 评论 -
队列的静态数组实现方式(C++版)
队列的静态数组实现方式<==>循环队列基础代码:#include<stdio.h>#include<stdlib.h>#define MaxSize 10 //队列中元素的最大个数#define ElemType int#define null NULL typedef struct{ ElemType data[MaxSize]; //用静态数组存放队列元素 int front,rear; //队头指针、队尾指针 }原创 2021-07-05 18:34:05 · 179 阅读 · 0 评论 -
共享栈的实现(C++版)
共享栈(两个栈共享同一块内存空间)只能是基于静态数组实现基础代码:#include<stdio.h>#include<stdlib.h>#define MaxSize 50#define null NULL#define ElemType inttypedef struct { ElemType data[MaxSize]; int top0; //0号栈的栈顶指针 int top1; //1号栈的栈顶指针 }ShareStac原创 2021-07-05 15:59:00 · 620 阅读 · 0 评论 -
栈的链表实现方式(C++版)
栈的链表实现也有两种,一种是带头结点的链表的实现方式,一种是不带头结点的链表的实现方式。原创 2021-07-03 22:37:50 · 803 阅读 · 1 评论 -
栈的静态数组实现方式(C++版)
用数组实现栈也有两种写法。第一种:栈空:S.top==-1;栈满S.top==MaxSize-1;top指针指向的是栈顶元素。基础代码如下:#include<stdio.h>#include<stdlib.h>#define MaxSize 50 //栈中最大元素的个数 #define ElemType inttypedef struct { ElemType data[MaxSize]; //存放栈中的元素 int top;原创 2021-07-02 14:24:07 · 438 阅读 · 0 评论