经典算法学习
文章平均质量分 70
我会在专栏中和大家分享最为经典的数据结构和算法原理和实现。以及包括一些经典面试题、编程题的算法实现。希望我们能在交流中实现共同进步,成为算法大神。
乞力马扎罗的雪CYF
一只不孤独的猿。
展开
-
C语言中的那些库函数(持续更新中)
1.【exit()】 exit是在调用处强行退出程序,运行一次程序就结束。exit(0)表示正常退出。exit(1)表示异常退出,这个1是返回给操作系统的。无论是写在main函数中,还是在其他函数中,都是程序退出。一般都是认为0是正常退出、其他数字是异常退出。所在的头文件是stdlib.h. 返回值的意义其实同main函数中的return一样,零表示正常,非零表示异常。2.【mem原创 2016-02-24 23:31:12 · 4724 阅读 · 2 评论 -
经典算法学习——非递归遍历二叉树
我们知道二叉树是一种递归定义的数据结构,包括二叉树的创建、遍历、求树高、叶子节点个数等等。使用递归来进行以上操作非常的简便,相关实现请参考 《C语言实现二叉树的基本操作》。但是今天我们剑走偏锋,使用非递归的方式来实现树的先序、中序、后序遍历。实现代码上传至 https://github.com/chenyufeng1991/TraverseBinaryTreeNoRecursion 。(1)非递原创 2016-10-03 12:28:03 · 3261 阅读 · 0 评论 -
经典算法学习——求二叉树的高度
二叉树是一种递归定义的数据结构,我们对它做的几乎所有的操作都是递归的。求树的高度也是如此。分别求左右子树的高度,然后取较长的子树作为高度。代码上传至 https://github.com/chenyufeng1991/BinaryTreeHeight 。核心代码如下:int BinaryTreeHeight(Node *node){ int treeHeight = 0; if原创 2016-10-02 21:10:39 · 17018 阅读 · 1 评论 -
经典算法学习——求二叉树叶子节点的个数
二叉树的叶子节点是既没有左子树又没有右子树的特殊的节点,使用递归我们可以方便的计算出共有多少叶子节点。代码上传至 https://github.com/chenyufeng1991/BinaryTreeLeafCount 。核心代码如下:int leafCount = 0;void LeafCountBinaryCount(Node *node){ if (node == NULL原创 2016-10-02 18:27:03 · 10661 阅读 · 1 评论 -
经典算法学习——求二叉树节点和为sum的路径
在一棵二叉树中,有多少个叶子节点,就会有多少条从根节点到叶子节点的路径。如果给每一个节点一个data值,那么每一条路径经过的节点data加起来就为sum,现在根据给定的sum,请找出有哪些路径符合这个sum。代码上传至 https://github.com/chenyufeng1991/BinaryTreePath 。 整体思路就是递归的去检索,每当经过一个节点的时候,就把节点值放入原创 2016-10-02 12:20:55 · 4575 阅读 · 0 评论 -
经典算法学习——求包含某两个字符的最小子串的长度
碰到这样一道算法题:给定一个字符串,比如: cadacacbedffffreaaawc ,然后给定两个字符为f,c ,那么最短子串的长度为5。因为子串有cbedf,freaaawc. 这篇博客考虑的比较简单,是只有两个字符的情况,我会在后续的博客中讲解如果需要包含多个字符那么应该如何处理。本篇的代码上传至 https://github.com/chenyufeng1991/MaxLengt原创 2016-10-02 10:19:17 · 3163 阅读 · 0 评论 -
经典算法学习——层序遍历二叉树
我们可以用很多方式去遍历一颗二叉树,比如先序遍历,中序遍历,后序遍历,其实都是通过递归的来实现。今天我们来对二叉树进行层序遍历,层序遍历的时候需要借助另一种数据结构——队列。本篇的示例代码上传至 https://github.com/chenyufeng1991/LevelOrderBinaryTree 。 层序遍历的基本思路是,当访问到一个节点的时候,把它放入队列,然后访问该值,同时原创 2016-10-01 17:16:44 · 3979 阅读 · 0 评论 -
经典算法学习——交换二叉树的左右子树(二叉树的翻转)
对于二叉树,我们必须熟练掌握它的各种操作,今天我们要来实现二叉树的翻转,也就是交换左右子树。具体思路不难,如果一个节点是叶子节点,则不做操作;如果一个节点只有左孩子或者右孩子,则进行交换,原来的孩子为空;如果一个节点既有左孩子和右孩子,则交换左右孩子。详细代码上传至 https://github.com/chenyufeng1991/ReverseLeftRightChild。核心代码如下://原创 2016-10-01 11:41:43 · 26902 阅读 · 2 评论 -
经典算法学习——求次方函数实现
在如今很多的笔试面试中,都会出现让你实现某个函数的,并且进行优化,比如降低时间复杂度。而在手写代码中,求次方函数是很高频的考点。示例代码上传至:https://github.com/chenyufeng1991/PowerFunction。题目如下:实现 double power(double x, int n)函数,实现求x的n次方。注意,n有可能为正或者负。(1)最简单的实现,循环// 最原创 2016-09-30 11:37:50 · 4461 阅读 · 1 评论 -
C++中字符串和数字相互转化实现
在刷一些题目的时候,总是会碰到字符串和数字进行转化的问题,今天我们就在C++中来用多种方法实现。示例代码上传至 https://github.com/chenyufeng1991/TransferStringAndInt 。(1)string -> char *// string -> char * string str3 = "chenyufeng"; const char *s原创 2016-09-28 22:45:29 · 4340 阅读 · 0 评论 -
C++ STL学习——heap
heap堆其实是一种比较复杂的数据结构,尤其涉及到建堆和调整堆的时候。好在在STL中已经封装了heap的一些操作,可以让我们比较方便的使用堆。比如判断堆,删除一个元素,插入一个元素,以及堆排序。示例代码上传至 https://github.com/chenyufeng1991/STL_heap 。(1)首先导入头文件.(2)这里使用数组来存储一个堆,也就是堆化数组,为了方便使用,我把数组转化为ve原创 2016-09-28 20:11:10 · 2929 阅读 · 0 评论 -
C++ STL学习——algorithm
在之前的博客中我们学习了很多STL中的模板库,包括deque,queue,stack,list等,他们都是一种数据结构,也就是说STL已经为我们实现了。今天我们来讲讲STL中比较大的一个库. 主要是一些算法的运算的实现,示例代码上传至 https://github.com/chenyufeng1991/STL_algorithm 。 在使用STL中的algorithm之前,需要导入头原创 2016-09-24 11:54:00 · 4481 阅读 · 1 评论 -
C++ STL学习——deque
在数据结构中还有一种很常见的队列叫做双端队列,我们在上一篇博客《C++ STL学习——queue》中讲到的队列queue是一种最标准的队列,只能在尾部插入数据,在头部删除数据。而今天我们讲到的deque分别可以在两端进行插入与删除,可以说用起来更加的灵活。示例代码上传至 https://github.com/chenyufeng1991/STL_deque 。(1)创建一个deque deq原创 2016-09-07 00:05:30 · 2937 阅读 · 0 评论 -
C++ STL学习——queue
我们在上一篇博客中《C++ STL学习——stack》简单介绍了STL 中stack这种数据结构的使用,这篇博客主要来讲一下queue队列的使用。其实queue的使用和stack一样简单。示例代码上传至 https://github.com/chenyufeng1991/STL_queue 。(1)首先要引入头文件 #include . 并使用命名空间 using namespace std原创 2016-08-23 00:08:23 · 3710 阅读 · 0 评论 -
C++ STL学习——stack
栈是最为常用的数据结构了,很多算法都是依靠栈来实现的,比如递归。我们要手动来实现栈,显得十分繁琐和麻烦,而且复用性不好。C++ 的STL中已经帮我们封装好了栈,我们只要方便的进行调用即可。该篇博客主要介绍STL 中stack的使用,stack应该说是STL中最简单的容器了。实例代码上传至 https://github.com/chenyufeng1991/STL_stack 。(1)首先引入头文原创 2016-08-22 23:50:45 · 3040 阅读 · 0 评论 -
C++ STL学习——list
如果由我们自己来实现一个链表,会写上不少代码,包括要实现创建、删除、插入等等操作。但是如果我们用了STL,那么该模板库就为我们提供了一个双向链表list,可以让我们非常方便的实现链表操作。要使用list,首先要引入头文件 #include .相关的示例代码上传至 https://github.com/chenyufeng1991/STL_list 。(1)创建list list lis原创 2016-08-22 00:00:56 · 2457 阅读 · 0 评论 -
C++ STL学习——vector
学过C++的人肯定会很熟悉STL标准模板库,STL其实就是封装了一系列的接口,供我们调用。很多函数或者算法的实现不需要我们从头开始写,大大提高我们的编程效率。这篇博客在简单介绍STL的情况下,会详细的来介绍vector的使用。 STL共有六大组件:一。容器(Container):是一种数据结构,如list,vector,deque,queue等,以模板类的方法提供,为了访问容器中的数据,可原创 2016-08-21 21:45:08 · 3959 阅读 · 0 评论 -
经典算法学习——打印两个链表的第一个公共节点
求链表的公共节点是一道很经典的算法题,并不是很难。我们需要知道的是,一旦两个链表有一个公共节点的话,那么这两个链表的形状就是一个“Y”型。也就是说,自公共节点之后的所有节点都是一样的。如下:其实只要看了这幅图,实现就很简单了。首先我们分别遍历两个链表,分别得出他们的长度L1,L2。然后在查找公共节点时,先在长的那个链表中走|L1-L2|步,然后两个链表同时向后进行同步遍历,每走一步时,就判断后面那原创 2016-08-21 20:24:43 · 2050 阅读 · 0 评论 -
经典算法学习——第一个只出现一次的字符
这同样是剑指Offer中的很经典的一道面试题。题目描述为:在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”,则输出'b'. 一开始大家就会想到最简单的方法就是每访问到一个字符的时候,与后面的每一个字符去进行比较,若没有发现相同的元素,那么该元素就是第一个只出现一次的字符。这样的复杂度为O(n^2). 显然这样的效率不高。 这道题的大方向就是一题查找算法,常见的查原创 2016-08-21 19:58:06 · 2312 阅读 · 0 评论 -
经典算法学习——合并两个有序链表
类似的,合并两个有序的数组或者链表也是剑指Offer中的经典题型。题目描述如下:输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是按照递增排序的。我这里以合并链表来实现。 在这里,并不需要去创建一个新的链表,只要有三个节点指针就行,第一个节点指针Node1指向第一个链表,第二个节点指针Node2指向第二个链表,第三个节点指针Node3指向新的链表。简单的示意图如下:当下一个原创 2016-08-21 16:59:45 · 2678 阅读 · 0 评论 -
经典算法学习——链表中倒数第k个节点
这是剑指Offer中非常经典的一道题,也是在面试笔试中高频出现。题目的详细描述如下:输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,从1开始计数,即链表的尾结点是倒数第一个节点。 本题有一个非常直观的解法,就是对链表扫描两遍,第一遍用来记录链表长度为n,第二次从链表头部走(n-k+1)步后,找到的那个节点就是倒数第k个节点。这种算法的问题就是需要扫描链表两遍,显得不是原创 2016-08-21 16:30:54 · 2018 阅读 · 0 评论 -
经典算法学习——在O(1)时间删除链表节点
这道算法题同样是剑指Offer中的一道题,题目描述为:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间内删除该节点。其实我们知道,想要在单向链表中找到某个节点并删除它,复杂度为O(n),因为必须从头遍历才能找到它(最重要的是因为要找到它的前一个节点。)所以想要O(1)完成,必须想其他的方法。 目前重要的一个信息就是已经有一个节点指针指向当前要删除的节点。这就比较好办了。我们原创 2016-08-21 13:26:54 · 2000 阅读 · 0 评论 -
C++ STL学习——string
当我们一开始使用C语言来处理字符串的时候,会感觉非常的麻烦。C语言中缺少相应的字符串处理函数,如果想要实现某个字符串功能,只能靠我们自己来实现。但是当来到C++中,字符串的处理就会变得异常简单。今天我们就来学习一下C++中最高频的字符串处理函数。示例代码上传至:https://github.com/chenyufeng1991/CppString。 首先要引入C++中的字符串头文件:#i原创 2016-08-21 11:37:53 · 2960 阅读 · 0 评论 -
经典算法学习——逆转链表
链表在数据结构中是一种非常重要的线性数据结构,也是各类面试笔试中常常涉及的问题。其中最常见的一个问题就是“输入一个链表的头结点,从尾到头反过来打印出每个节点的值”,简单说就是逆转链表。当然,有人会发现,这其实就是剑指Offer中的一道题。这道题的实现我已经上传至 https://github.com/chenyufeng1991/ReverseLinkedList_Stack 。 这道原创 2016-08-07 16:51:41 · 4971 阅读 · 0 评论 -
经典算法学习——最小的k个数
经常面试的同学可能会遇到这个问题,即输出数组中的最小的k个数。同样的,这也是剑指Offer上面的一道题。这道题最简单的思路莫过于把输入的n个整数排序,排序之后位于最前面的k个数就是最小的k个数。这样实现的复杂度为O(nlogn)。如果大家看了上一篇博客《经典算法学习——数组中出现次数超过一半的数字》后,其实会发现两道题的思路是一样的,也就是要找到一个index值,它的前面都比它小,后面的都比它大。原创 2016-08-06 20:27:24 · 2057 阅读 · 0 评论 -
经典算法学习——数组中出现次数超过一半的数字
首先这道算法题并不是很难,看过剑指Offer的同学都知道这是里面的一道题。在各大公司的面试中也是经常被用到的,今天我们就采用最常规的方法来实现一下。 首先有人会想到,如果能把数组排序后,那么中间的那个数字就是超过一半的那个数字了(如果存在的话)。当然排序较快的复杂度为O(nlogn).这种方法完全可以实现,但未必是最好的。 因此,面试中最常规的解法就是使用快速排序中的Par原创 2016-08-06 17:31:17 · 2303 阅读 · 0 评论 -
经典算法学习——斐波那契数列
在我们学习算法的过程中,斐波那契数列肯定是会碰到的一个东西,其实我们并不是为了学习一个简单的数列,更重要的是学习他的思想——递归。个人觉得递归是解决很多算法问题最高频的方法了。递归最简单的描述就是一个函数自己调用自己,达到一个条件的时候,递归结束。比如我们在以下场景常常用递归:快速排序、归并排序、二叉树的多种遍历方法等等。对于C语言实现斐波那契数列的代码已经上传至 https://github.c原创 2016-08-06 14:34:59 · 2761 阅读 · 0 评论 -
经典算法学习——二分查找
在所有的查找算法中,二分查找是最简单一种。二分查找要求原先的序列是已经排序的,每次都是以序列中间的数字作为比较,如果小于中间的数字,那么就在序列左边继续递归查找;如果大于中间的数字,那么就在序列右边继续递归查找。直到找到该数字,或者直到序列中只有一个数字的时候都还没找到,则查找失败。查找的时间复杂度可以达到O(logN),应该说是除了数组按下标查找O(1)以外的最快的查找方式了。示例代码上传至 h原创 2016-08-06 13:47:32 · 2122 阅读 · 0 评论 -
C语言实现二叉查找树(BST)的基本操作
我们在上一篇博客中讲解了二叉树,这一次我们来实现二叉树的进阶——二叉查找树(Binary Search Tree),又称二插排序树(Binary Sort Tree)。所以简称为BST。二插查找树的定义如下:1.若左子树不为空,则左子树上所有节点的值均小于它的根节点的值;2.若右子树不为空,则右子树上所有节点的值均大于它的根节点的值;3.左右子树也分别为二叉排序树;二叉排序树的一个重要特点就是中序原创 2016-03-16 00:23:08 · 12796 阅读 · 3 评论 -
C语言实现二叉树的基本操作
我在前面的博客中讲解了链表、栈和队列,这些数据结构其实都是线性表,并且给出了详细的实现。从今天开始,我们将要来学习树,树作为一种数据结构我们经常会用到,作为起步和基础,我们先来实现二叉树,也就是每个节点有不超过2个子节点的树。对于树的操作,最基本的创建、遍历、求树高、节点数等。代码上传至 https://github.com/chenyufeng1991/BinaryTree 。(1)节点的定义t原创 2016-03-11 21:45:03 · 27041 阅读 · 4 评论 -
C语言使用非循环双向链表实现队列
在前面两篇博客中,我分别使用了静态数组和动态数组来模拟循环队列。但是线性表中和队列最神似的莫过于链表了。我在前面也使用了大量的篇幅来讲述了链表的各种操作。今天我们使用一种比较特殊的链表——非循环双向链表来实现队列。首先这里的说明的是构建的是普通的队列,而不是循环队列。当我们使用数组的时候创建循环队列是为了节省存储空间,而来到链表中时,每一个节点都是动态申请和释放的,不会造成空间的浪费,所以就不需要原创 2016-03-09 23:17:21 · 4975 阅读 · 0 评论 -
C语言实现使用动态数组实现循环队列
我在上一篇博客《C语言实现使用静态数组实现循环队列》中实现了使用静态数组来模拟队列的操作。由于数组的大小已经被指定,无法动态的扩展。所以在这篇博客中,我换成动态数组来实现。动态数组可以不断开辟内存空间,只是会在数组的初始化时有所不同,其他对数组的操作都是一样的。代码上传至 https://github.com/chenyufeng1991/Queue_DynamicArray 。(1)声明变量st原创 2016-03-07 09:18:34 · 6377 阅读 · 3 评论 -
C语言实现使用静态数组实现循环队列
队列是一种先进先出的的数据结构,我们同样可以使用数组、链表等来实现。我们可以在队列的尾部进行插入元素,在队列的头部取出元素。普通的队列由于空间利用率不高,所以我们一般都用循环队列。循环队列中最重要的的两个操作就是判断是否为空和是否已满。当head==tail时,表示队列为空。当(tail+1)%MAX_SIZE == head,表示队列已满。 我判断队满的方法:牺牲一个单元来区分对空和原创 2016-03-06 22:39:15 · 10361 阅读 · 3 评论 -
C语言实现使用带头结点的单链表来构造栈结构
我在前面两篇博客中分别使用了静态数组、动态数组两种方式来构造栈,实现起来很方便,但总觉得灵活性还不够,因为无论怎样,我们都是要指定数组的长度。这篇博客中我们将会使用带头结点的单链表来模拟栈。为什么选用单链表呢?因为对于栈来说,弹出、压入等操作都是对栈顶来操作的。而单链表对第一个节点的操作是最为方便的。两者刚好能对应起来。代码上传至 https://github.com/chenyufeng1991原创 2016-03-06 17:26:30 · 5763 阅读 · 0 评论 -
C语言实现使用动态数组来构造栈结构
我在面前一篇博客《C语言实现使用静态数组来构造栈结构》中使用了静态数组来模拟栈的操作。静态数组的大小是在代码中写死的,是存储在用户栈上面的,使用起来不灵活。在这篇博客中我会使用动态数组来构造,此时使用的内存是动态申请的,只是在数组的创建和释放上面有差别,其他的使用都一样。注意:动态申请的内存需要我们手动去释放,因为这些占用的内存是在运行时堆上,不会在程序退出后释放。而存放在栈上面的会在程序退出后自原创 2016-03-06 15:10:07 · 5030 阅读 · 0 评论 -
C语言实现使用静态数组来构造栈结构
在数据结构中,栈是一种很重要的存在。这是一种先进后出的结构,就像一个“死胡同”一样。今天我们先用最简单的方式静态数组来模拟栈。代码上传至 https://github.com/chenyufeng1991/Stack_StaticArray 。(1)声明栈的大小,数组,和一个栈顶指针。栈顶指针可以取出栈顶的数据。#define STACK_SIZE 50static int stack[STA原创 2016-03-06 11:34:58 · 4870 阅读 · 0 评论 -
经典算法学习——非循环双向链表实现冒泡排序(带头结点尾结点)
我在之前的博客中分别对三种不同的链表进行了冒泡排序,区分的类型有单链表和双向链表,有带头结点的和不带头结点的。其实实现的整体思路是一样的,分别以(n-1)次遍历链表,比较前后两个节点的大小并判断是否交换。为了学习的完整性,在这篇博客中我们将会来实现对带头结点尾结点的双向非循环链表进行冒泡排序。代码上传至 https://github.com/chenyufeng1991/DoubleLinkedL原创 2016-03-04 23:05:19 · 4667 阅读 · 0 评论 -
C语言实现双向非循环链表(带头结点尾结点)的节点插入
对于双向链表,个人推荐使用带头结点尾结点的方式来处理会比较方便。我在《C语言实现双向非循环链表(不带头结点)的节点插入》中详细实现了在不带头结点的情况下的插入。这次我们将会来在使用头结点尾结点的情况下在任意的位置插入元素。代码上传至 https://github.com/chenyufeng1991/InsertNodeDoubleLinkedList_HeadNode 。核心代码如下://插入一原创 2016-03-04 16:18:08 · 3172 阅读 · 0 评论 -
C语言实现非循环双链表节点的删除(带头结点尾结点)
我在之前一篇博客《C语言实现非循环双链表节点的删除(不带头结点)》中详细讲解了不含头尾节点的双链表中删除一个节点,处理过程还是稍显麻烦。自从我们学习使用头尾节点来处理双链表后,删除过程就非常方便。代码上传至 https://github.com/chenyufeng1991/DeleteNodeDoubleLinkedList_HeadList 。核心代码如下://删除pos位置的节点int D原创 2016-03-04 13:03:01 · 3690 阅读 · 0 评论 -
C实现头插法和尾插法来构建双向非循环链表(带头结点尾结点)
双向链表中如果有了头结点和尾结点,对于头插法和尾插法就显得非常方便。这样在尾部插入一个元素也就不用去遍历链表了。个人建议使用这种链表来处理问题。代码上传至 https://github.com/chenyufeng1991/HeadInsertAndTailInsert_DoubleList_HeadList 。核心代码如下://创建带头结点和尾结点的双向非循环链表(头插法)void Head原创 2016-03-04 10:49:43 · 5616 阅读 · 1 评论