数据结构
文章平均质量分 69
yang20141109
这个作者很懒,什么都没留下…
展开
-
深度优先遍历之边的分类
根据在图G上进行深度优先搜索所产生的深度优先森林,可以把图中的边分为四类:(1)树边:是深度优先森林中的边。如果顶点v是在探测边(u,v)时首次被发现的,那么(u,v)就是一条树边。(2)反向边:是深度优先树中,连接顶点u到它的某一祖先顶点v的那些边。有向图中可能出现的自环也被认为是反向边。(3)正向边:是指深度优先树中,连接顶点u到它的某个后裔v的非树边(u,v)。(4)交叉边:原创 2015-10-20 21:46:39 · 3008 阅读 · 0 评论 -
递归与非递归遍历二叉树(前序、中序、后序)
二叉树前序遍历:(1)访问根结点(2)按照前序遍历左子树(3)按照前序遍历右子树递归实现前序遍历的代码:void preOrder(BiTNode *root){ if(root != NULL) { coutval<<endl; preOrder(root->lchild); preOrder(root->rchild); }}二叉树中序遍历(1)按照中序遍原创 2016-01-05 21:54:35 · 812 阅读 · 2 评论 -
二分查找(递归与非递归)
二分查找的思想是:我们设置三个指针low,mid和high,low指向数组的第一个元素,mid指向数组中间元素,high指向数组最后一个元素。每次用待查元素和中间元素比较,如果待查元素比中间元素小,那么我们更新high = mid - 1,如果待查元素比中间元素大,那么我们更新low = mid + 1,如果待查元素和中间元素相等,那么我们返回mid。重复上述过程,直到检索成功或检索区间长度为0(原创 2016-01-06 11:22:02 · 476 阅读 · 0 评论 -
插入排序(顺序数组中找要插入元素的位置)
插入排序的算法思想十分简单,就是对待排序的数组进行处理,数组中的每个元素都同已排好的数组中的元素进行比较,然后插入到适当的位置。插入排序关键在于如何将待排元素插入到已经排好数组中的适当位置。方法一:使用顺序查找的方法,找到待排元素要插入的位置。/*插入排序:空间复杂度为o(1);数组为正序排列时,直接插入排序的时间复杂度为o(n);数组为逆序排列时,直接插入排序的时间复杂度为o原创 2015-10-08 09:56:25 · 1273 阅读 · 0 评论 -
使用for循环输出字符串的子序列
方法一:1.输出字符串长度为len的所有后缀子序列。2.循环输出长度为len-1,len-2字符串的后缀子序列。void printSubString(string str){ if (str.empty()) return; int size = str.size(); //输出字符串长度为size,size-1,size-2,...,1所有后缀 for (int i =原创 2016-03-17 11:50:21 · 1347 阅读 · 0 评论 -
基数排序
基数排序:首先分配10个桶,桶的编号为零到九。按照最低位的有效数字插入到相应的桶中。然后按照次低位插入到相应的桶中。//基数排序#include#include#includeusing namespace std;void radixSort(vector &arr){ //判断当前数组是否为空 if (arr.empty()) return; //找到数组中最大的元素原创 2016-04-02 16:30:42 · 323 阅读 · 0 评论 -
二叉树中从根结点到叶子结点所有路径(非递归实现)
非递归实现输出二叉树中从根节点到叶子节点的所路径,我们用非递归的方法实现。我们在存储节点时,用一个标记域标记从当前节点出发的所有路径是否已经被访问过。如果当前节点的所有路径都被访问过,则标记域为一,只要有一条路径没有被访问过,那么标记域就是零。//存储路径的数组(存储的是当前节点的指针)vector path(10, NULL);//非递归实现从根节点到叶子节点的全路径(前序遍历二叉树的思想原创 2016-03-11 16:51:06 · 4093 阅读 · 0 评论 -
二叉树中从根结点到叶子结点的所有路径(递归实现)
假设我们要输出二叉树中所有从根节点到叶子节点的所有路径,我们采用前序遍历二叉树的思想,每遇到一个节点,我们把该节点存储在数组中,然后判断该节点是否为叶子节点,如果是叶子节点,我们输出从根节点到该叶子节点的路径,并且在数组相应位置置空。如果不是叶子节点,我们递归进入该节点的非空子节点中。#include#include#include#includeusing namespace std;原创 2016-03-11 10:05:22 · 8028 阅读 · 0 评论 -
单链表进行归并排序
对单链表进行归并排序:首先设置两个指针slow和fast,slow指针每次走一步,fast指针每次走两步,当fast指向末尾元素或者指向空时,slow指针刚好走到链表的中间位置,此时slow指针恰好把链表分为左右两部分,slow->next指针指向第二部分的首部,然后我们递归的对两部分进行划分操作,最后划分到两部分都只有一个元素时,我们对其进行合并操作,然后依次递归的向上进行归并操作。时间复杂度为原创 2016-04-30 19:57:13 · 1140 阅读 · 0 评论 -
判断两条线段是否相交
题目:给定两条线段,判断这两条线段是否相交,线段AB的表示形式是A(x1,y1)B(x2,y2),线段CD的表示形式为C(x3,y3)D(x4,y4)。那么我们如何判断线段AB与线段CD是否相交。 解析:在介绍如何解决线段相交问题之前,我们先介绍向量的叉积。如下图所示: 下面的图(1)表示p1向量在p2向量的顺时针方向,图(2)表示p1向量在p2向量逆时针方向,图(3)原创 2016-05-28 11:15:00 · 835 阅读 · 0 评论 -
链表进行插入排序
插入排序:在已排好序的序列中,找到当前要排序元素的插入位置即可。如果我们对链表进行排序,我们只需要找到当前插入位置的前一个指针即可。然后当前元素向前移动一位。//对单向链表进行快速排序#include#includeusing namespace std;//链表数据结构struct ListNode{ int val; ListNode *next;};//在链表末尾追加原创 2016-04-22 22:05:19 · 1930 阅读 · 0 评论 -
逆波兰表达式求值
给出一个逆波兰表达式,求该逆波兰表达式表达式的值。比如: ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6 解析:用栈来实现,遍历当前字符串,如果当前字符串可以转换为数组类型,则当前元素转换为数值,并且入栈,如果是运算原创 2016-04-22 22:33:48 · 593 阅读 · 0 评论 -
非递归版本的快速排序
快速排序:每次选择一个枢轴,比枢轴大的元素放在数组的右半部分,比枢轴小的元素放在数组的左半部分。然后递归的进入数组的左右两半部分。如果要用非递归来实现,我们需要用栈来保存数组左右两半部分的边界。代码如下:int partition(vector &nums, int start, int last){ int val = nums[last]; while (start < last) {原创 2016-07-21 16:13:30 · 382 阅读 · 0 评论 -
单链表进行快速排序
单链表进行快速排序:选择尾元素作为枢轴,根据枢轴值把链表划分为两部分,前半部分值小于枢轴值,后半部分值大于枢轴值,划分函数的返回值为指向排好序链表枢轴前一个元素的指针。这个指针有可能是空指针,我们需要做特殊判断。在快排函数中,我们需要对空指针做特殊处理。以下是完整版代码://对单向链表进行快速排序#include#includeusing namespace std;//链表数据结构s原创 2016-04-14 16:30:26 · 848 阅读 · 0 评论 -
单源点最短路径
单源最短路径:从顶点v可达顶点u表示为v->u,在所有的可达路径中存在一条权值最小的路径,则这条路径叫做v到u的最短路径。那么单源最短路径指的是:求出给定源点s到其他所有顶点的最短路径。最短路径的性质:对于一给定的带权图G=(V,G),所定义的加权函数为w:E->R。设p=是从v1到vk的最短路径。对于任意i,j,其中1为p中从顶点vi到顶点vj的子路径。那么,pij是从vi到vj的最短路径。原创 2015-12-03 11:04:58 · 1201 阅读 · 1 评论 -
双向Dijstra算法
双向Dijstra算法:在无向带权图中,求从s到t最短路径。双向Dijstra算法的思想是:分别从s顶点和t顶点开始执行单向Dijstra算法,从s点开始执行的Dijstra算法定义为前向Dijstra搜索,从t点开始执行Dijstra算法定义为后向Dijstra搜索。算法结束的条件是:前向(后向)Dijstra搜索求得当前最短路径上的顶点为u,且在后向(前向)Dijstra搜索已经计算出到u的最原创 2015-12-17 16:30:30 · 4887 阅读 · 1 评论 -
广度优先搜索之最短路径
广度优先搜索算法可以得到从已知源点到每个可达顶点的最短距离,此时的最短距离指的是路径上边的个数最少,使用parent数组记录当前顶点的父节点,比如parent[u] = v表示u的父节点为v。最短路径的长度记录在d数组中,比如d[v] = 3表示从源点(s)到v的最短路径为3。最后我们使用showPath()函数把最短路径输出。#include#include#include#include原创 2015-10-20 17:36:50 · 6337 阅读 · 3 评论 -
冒泡排序
冒泡排序的算法思想就是不停的比较相邻的元素值,如果不满足排序要求,就交换相邻记录,直到所有的元素都已经排好序为止。每次找到最大元素,把此元素放在最后。与插入排序不同的是,冒泡排序在对第i个元素进行排序时,不需要改动已排好序的的元素。冒泡排序是稳定的排序算法,最小的时间代价为o(n),最大时间代价为o(n*n),平均时间代价为o(n*n)。#includeusing namespace std原创 2015-10-08 17:29:47 · 291 阅读 · 0 评论 -
归并排序
归并排序简单地将原始数组划分为两个子数组,然后对每个子数组递归的排序,最后再将有序子数组合并,归并排序的主要步骤为:(1)将数组划分为两个子数组。(2)分别对两个子数组递归进行合并排序。(3)将这两个已经排好序的子数组合并为为一个有序的数组。归并排序是一种基于分治法的排序。归并排序的总的时间代价为o(nlogn),空间复杂度为o(n)。原始优化的归并排序:#includ原创 2015-10-09 20:19:04 · 503 阅读 · 1 评论 -
堆排序
堆有两种:最大堆和最小堆。我们介绍最小堆的排序算法。最小堆满足的条件:堆中每个父节点的值都要小于或等于其孩子节点的值。因此,最小堆的堆顶元素的值就是整个堆中的最小记录。堆排序的时间复杂度为o(nlogn)。建立堆的时间复杂度为o(N)。堆排序主要包括两个步骤:(1)对所有的元素建立最小堆。(2)取出堆顶元素与数组中的最后一个元素交换。#includeusing namespace原创 2015-10-08 16:43:23 · 229 阅读 · 0 评论 -
选择排序
选择排序的算法思想是逐个找出第i小的元素,并将这个元素与数组中的第i个位置的元素进行交换,第i小的元素 一次交换到位。选择排序是不稳定的排序算法。整个排序过程中最多需要n - 1次交换,选择排序总的时间代价为o(n * n),算法不依赖于原始数组的输入顺序,因此最大,最小,平均时间代价均为o(n * n)。#includeusing namespace std;void select_s原创 2015-10-08 10:52:40 · 268 阅读 · 0 评论 -
桶排序
桶排序是一种十分简单的分配排序,数组中元素值的范围在[0,max),如果事先知道每个桶中有多少个元素,就可以对原数组进行排序。我们使用一个额外的大小为max数组记录每个元素出现的次数,额外数组的下标表示原数组中值的大小,我们遍历额外数组,每次访问一个元素,我们把它的下标记录在原数组中。例如当max = 10时,我们对数组arr{7,3,8,9,6,1,8,1,2},我们分配一个大小为10的额外数组原创 2015-10-10 15:42:04 · 321 阅读 · 0 评论 -
败者树
败者树:主要应用在外排序中,减少外排序内部排序的比较次数。在双亲节点记下刚进行完的这场比赛的败者,让胜者去参加更高一层的比赛,另外,根节点处加入一个节点来记录整个比赛的的赢者。便可以得到一棵败者树。败者树中的每个分支节点记录了比赛失败者而不是胜利者的索引。创建败者树,我们用数组ls记录参加比赛的选手,ls中元素的值表示当前选手的得分,比如ls{10,9,20,6,12},我们要选出得分最小的参加者原创 2015-10-12 20:39:45 · 1625 阅读 · 0 评论 -
无向图中的广度优先生成森林
广度优先生成森林的思路和深度优先生成森林的思路相同,在此不再复述,请看上一篇。#include#include#include#include#include#includeusing namespace std;struct CSTree{ int data; CSTree * lchild; CSTree * nextsibling;};void BFSTree(原创 2015-10-14 20:40:31 · 3580 阅读 · 0 评论 -
图的遍历之深度优先搜索
深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。假设初始状态是图中所有的顶点未曾访问过,则深度优先搜索可从从中某个顶点出发,访问该顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问过,则另选图中一个未曾访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问过为止。当以邻接表作图的存储结构时,深度优先搜索遍历原创 2015-10-13 16:51:05 · 1091 阅读 · 0 评论 -
图的遍历之广度优先搜索
广度优先搜索遍历类似于树的按层次遍历的过程。假设从图中某个顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使用”先被访问的顶点的邻接点“先于”后被访问的顶点的邻接点“被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则选图中一个未被访问的节点作为起始点,重复上述过程,直至图中所有顶点都被访问到为止。若用邻原创 2015-10-13 20:35:18 · 1069 阅读 · 0 评论 -
无向图中的深度优先生成森林
在对无向图进行遍历时,对于连通图,仅需要从图中的任意一个顶点出发,进行深度优先搜索或广度优先搜索,便可访问到图中所有顶点。对于非连通图,则需从多个顶点出发进行搜索,而每一次从一个新的起点出发进行搜索过程中得到的顶点访问序列恰为其各个连通分量中顶点集。对于非连通图,每个连通分量中的顶点集,和遍历时走过的边一起构成若干棵生成树,这些连通分量的生成树组成非连通图的生成森林。我们以孩子兄弟链表作为深度优先原创 2015-10-14 15:50:33 · 4655 阅读 · 1 评论 -
强连通分量
有向图的强连通分量是指:在强连通分量中的每一对顶点都存在一条路径可达,比如对于顶点对v和u,在强连通分量中v到u可达,那么u到v也可达。比如在左图中v1、v2、v3是一个强连通分量,v2也是一个强连通分量。强连通分量右图所示:原创 2015-10-16 10:31:45 · 696 阅读 · 1 评论 -
拓扑排序
在施工流程图或产品生产的流程图中,根据施工项目的顺序和产品生产顺序排序的过程,即拓扑序列。有向无环图的拓扑序列指的是:图中v1到v2有一条边,那么在拓扑序列中v1在v2之前,对于所有的顶点和边都适用。下面介绍两种求拓扑序列的方法:(1)在有向图中选择一个没有前驱的顶点输出。(2)从图中删除该顶点和所有以它为尾的弧。重复上述过程,直至全部的顶点输出,或者当前图中不存在无前驱的顶点为止。后原创 2015-10-15 21:06:48 · 1122 阅读 · 0 评论 -
快速排序
快速排序是对冒泡排序的一种改进。它的基本思想是,通过一趟排序将待排序数组分割成独立的两部分,其中一部分元素均比另一部分元素的值要小,则可以分别对这两部分元素继续进行排序,以达到整个数组有序,在代码实现中,我们选择最后一个元素作为枢轴。用枢轴把数组元素分割成两部分。平均时间复杂度为o(nlogn)。#include#includeusing namespace std;int part原创 2015-10-09 15:52:13 · 359 阅读 · 0 评论