面试之常用算法总结

面试中常常会遇到算法的问题 而基础算法的考核离不开链表和二叉树,下面是对这两种数据结构常见问题的总结

1、链表

#include<Stack>
#include<stdio.h>
#include<stdlib.h>

/*
    链表的总结 插入 删除以及遍历
    以及链表相关的应用
*/

// 链表的结构

// 插入 若第一个节点为空则需啊替换 所以传递的参数必须是指针的指针 否则修改无效

struct ListNode{
    int m_value;
    ListNode *m_pNext;
};

void addToTail(ListNode **pHead,int value)
{
        ListNode *pNew=new ListNode();
        pNew->m_value=value;
        pNew->m_pNext=NULL;
        if(*pHead==NULL)
        {
            * pHead=pNew;
            printf("%d ",(*pHead)->m_value);
        }else{

            ListNode *pNode=*pHead;
            while(pNode->m_pNext!=NULL )
            {
                pNode=pNode->m_pNext;
            }
            pNode->m_pNext=pNew;
            printf("%d ",pNode->m_pNext->m_value);
        } 

} 

// 删除链表中 指定值的节点

void RemoveNode(ListNode **pHead,int value)
{
    if(*pHead==NULL || pHead==NULL)
    {
        return ;
    }

    ListNode *pTODeleted=NULL;
    if( (*pHead)->m_value==value )
    {
        pTODeleted=*pHead;
        *pHead=(*pHead)->m_pNext;
    }else{

        ListNode *pNode=*pHead;
        while(pNode->m_pNext!=NULL && pNode->m_pNext->m_value!=value)
        {
            pNode=pNode->m_pNext;
        }

        if(pNode->m_pNext!=NULL && pNode->m_pNext->m_value==value)
        {
            pTODeleted=pNode->m_pNext;
            pNode->m_pNext=pNode->m_pNext->m_pNext;
        }    

    }

    if(pTODeleted!=NULL)
    {
        delete pTODeleted;
        pTODeleted=NULL;

    }
} 

// 从尾到头打印链表 两种方法 一种是使用递归 一种是使用栈 

// 递归
void printListNodeInvertedByRecursion(ListNode *pNode)
{

    if(pNode!=NULL)
    {
        printListNodeInvertedByRecursion(pNode->m_pNext);
         printf("%d ",pNode->m_value);
    }

} 

// 栈
void printListNodeInvertedByStack(ListNode *pNode)
{
    std::stack<ListNode*> nodes;

    while(pNode!=NULL)
    {
        nodes.push(pNode);
        pNode=pNode->m_pNext;
    }

    while(!nodes.empty())
    {
        ListNode *node=nodes.top();
        printf("%d ",node->m_value);
        nodes.pop();
    }
}

/* 在O(1)时间内删除链表节点
    问题:给定单向链表的头指针和一个节点指针 定义一个函数在O(1)时间内删除该节点
    链表节点与函数定义如下:
    struct ListNode
    {
        int m_value;
        ListNode *m_pNext;
    };

    void DeletedNode(ListNode **pListHead,ListNode *pToDeleted); 

*/ 

void DeletedNode(ListNode **pListHead,ListNode *pToDeleted)
{

    if(!pListHead || !pToDeleted)
    {
        return;
    }
    // 删除节点不是尾节点
    if(pToDeleted->m_pNext !=NULL)
    {
        ListNode *temp=pToDeleted->m_pNext;
        pToDeleted->m_pNext=temp->m_pNext;
        pToDeleted->m_value=temp->m_value;
        delete temp;
        temp=NULL;

    }else{
        // 只有一个节点
        if(*pListHead==pToDeleted)
        {
            delete pToDeleted;
            pToDeleted=NULL;
            *pListHead=NULL;
        }else{
            // 删除节点是尾节点
            ListNode *pNode=*pListHead;
            while(pNode->m_pNext!=pToDeleted)
            {
                pNode=pNode->m_pNext;

            }

            pNode->m_pNext=NULL;
            delete pToDeleted;
            pToDeleted=NULL;

        }

    }

} 

/*
    链表中倒数第k个节点

    解析:使用两个指针,一个指针先走k个节点,另一个指针指向头指针,
    然后一起往下遍历,当后一个指针指向尾指针时,前一个指针就是倒数第k个指针 

*/ 

ListNode *FindkthToTail(ListNode *pListHead,unsigned int k)
{

    if(pListHead==NULL || k==0)
    {
        return NULL;
    }

    ListNode *pHead=pListHead;
    ListNode *pBehind = NULL;
    for(unsigned int i=0;i<k-1;i++)
    {
        if(pHead->m_pNext!=NULL)
        {
            pHead=pHead->m_pNext;
        }else{
            return NULL;
        }
    }

    pBehind=pListHead;
    while(pHead->m_pNext!=NULL)
    {
        pHead=pHead->m_pNext;
        pBehind=pBehind->m_pNext;
    }

    return pBehind;
} 

/*
    反转链表 

    解法:在遍历链表的工程中修改next指向的节点 并将最后一个节点保存为头节点
*/

 ListNode *ReverseList(ListNode *pListHead)
{
    ListNode *pReverseHead=NULL;
    ListNode *pNode=pListHead;
    ListNode *pPrev=NULL;
    while(pNode!=NULL)
    {
        ListNode *pNext=pNode->m_pNext;
        if(pNext==NULL)
        {
            pReverseHead=pNode;
        }

       pNode->m_pNext=pPrev;

       pPrev=pNode;
       pNode=pNext;
    }

    return pReverseHead;
} 

/*
    合并两个排序链表
    题目;输入两个递增排列的链表,合并这两个链表并使新链表中的节点仍然是按照递增排序的。
    解析:递归
*/

ListNode *Merge(ListNode *pHead1,ListNode *pHead2)
{
    if(pHead1==NULL)
    {
        return pHead2;
    }else if(pHead2==NULL)
    {
        return pHead1;
    }

    ListNode *pMergeHead=NULL;

    if(pHead1->m_value > pHead2->m_value)
    {
        pMergeHead=pHead2;
        pMergeHead->m_pNext=Merge(pHead1,pHead2->m_pNext);

    }else{

        pMergeHead=pHead1;
        pMergeHead->m_pNext=Merge(pHead1->m_pNext,pHead2);
    }

    return pMergeHead;

}
int main()
{
    ListNode *pHead=NULL;
    for(int i=0;i<10;i++)
    {
        addToTail(&pHead,i);
    }

    putchar(‘\n‘);
    printListNodeInvertedByRecursion(pHead);
    RemoveNode(&pHead,9);
    putchar(‘\n‘);
    printListNodeInvertedByStack(pHead);
    putchar(‘\n‘);
    system("pause");
    return 0;
}

2.二叉树

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<Stack>
#include<Queue>
#include<vector>
/*
  重建二叉树 根据前序遍历和中序遍历 建立二叉树
*/ 

struct BinaryTreeNode
{
  int m_value;
  BinaryTreeNode *m_pLeft;
  BinaryTreeNode *m_pRight;

}; 

// 异常终止函数 到此,当出现异常的时候,
//程序是终止了,但是我们并没有捕获到异常信息,
//要捕获异常信息,我们可以使用注册终止函数atexit(),它的原型是这样的:int atexit(atexit_t func);

void Exception()
{
 printf("Invalid Input");
} 

// 根据前序遍历和中序遍历 构建二叉树
BinaryTreeNode *ConstructCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder);
BinaryTreeNode* ConstructTree(int *preorder,int *inorder,int length)
{
     if(preorder==NULL || inorder==NULL || length<=0)
     {
        return NULL;
     }    

     BinaryTreeNode *treeHead=ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
     return treeHead;
} 

BinaryTreeNode *ConstructCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
     int rootValue=startPreorder[0];
     BinaryTreeNode *root=new BinaryTreeNode();
     root->m_value=rootValue;
     root->m_pLeft=root->m_pRight=NULL;

     // 遍历到了最底层 返回叶子节点
     if(startPreorder == endPreorder)
     {
         if(startInorder==endInorder && *startInorder==*endInorder)
         {
            return root;
         }else{
               //throw exception("Invalid Input");
               atexit(Exception);
         }
     }

     int *rootInorder=startInorder;

     while(*rootInorder!=rootValue)
     {
         rootInorder++;
     }

     if(rootInorder==endInorder && *rootInorder!=rootValue)
     {
       //throw std::exception("Invalid Input");
       atexit(Exception);
     }

     int leftLen=rootInorder-startInorder;
     int *leftPreorderEnd=startPreorder+leftLen;

     if(leftLen>0)
     {
        root->m_pLeft=ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
     }
     if(leftLen<endPreorder-startPreorder)
     {
         root->m_pRight=ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
     }

     return root;
}

// 前序遍历

void preorderTraverse(BinaryTreeNode *treeNode)
{
     if(treeNode==NULL)
     {
        return;
     }

     printf("%d ",treeNode->m_value);
     if(treeNode->m_pLeft!=NULL);
     preorderTraverse(treeNode->m_pLeft);

     if(treeNode->m_pRight!=NULL)
     preorderTraverse(treeNode->m_pRight);

} 

// 中序遍历
void inorderTraverse(BinaryTreeNode *treeNode)
{

     if(treeNode->m_pLeft!=NULL)
     {
        inorderTraverse(treeNode->m_pLeft);
     }

     printf("%d ",treeNode->m_value);

     if(treeNode->m_pRight!=NULL)
     {
            inorderTraverse(treeNode->m_pRight);
     }

}

// 后序遍历
void postorderTraverse(BinaryTreeNode *treeNode)
{

     if(treeNode->m_pLeft!=NULL)
     {
        postorderTraverse(treeNode->m_pLeft);
     }

     if(treeNode->m_pRight!=NULL)
     {
         postorderTraverse(treeNode->m_pRight);
     }

     printf("%d ",treeNode->m_value);

}

// 宽度遍历 使用队列 

void BFS(BinaryTreeNode *root)
{
     // TODO
     std::queue<BinaryTreeNode *> treeNodes;
     treeNodes.push(root);

     BinaryTreeNode *node;
     while(!treeNodes.empty())
     {
        node=treeNodes.front();
        printf("%d ",node->m_value);
        treeNodes.pop();
        if(node->m_pLeft!=NULL)
        {
            treeNodes.push(node->m_pLeft);
        }

         if(node->m_pRight!=NULL)
        {
            treeNodes.push(node->m_pRight);
        }
     }

} 

// 深度遍历 使用栈
void DFS(BinaryTreeNode *root)
{
     std::stack<BinaryTreeNode *> treeNodes; 

     treeNodes.push(root);
     BinaryTreeNode *node;
     while(!treeNodes.empty())
     {
        node=treeNodes.top();
        printf("%d ",node->m_value);
        treeNodes.pop();
        if(node->m_pRight!=NULL)
        {
          treeNodes.push(node->m_pRight);
        }

        if(node->m_pLeft!=NULL)
        {
          treeNodes.push(node->m_pLeft);
        }
     }
}

/* 树的子结构
    题目:输入两棵二叉树A和B,判断B是否是A的子结构

    解析:分两步解决该问题,首先在A中寻找 和B头节点相同的节点
    然后比较这些节点组成子结构是否和B相同
*/

bool DosTree1HasTree2(BinaryTreeNode *pRoot1,BinaryTreeNode *pRoot2)
{
    if(pRoot2==NULL)
    {
        return true;
    }

    if(pRoot1==NULL)
    {
        return false;
    }

    if(pRoot1->m_value!=pRoot2->m_value)
    {
        return false;
    }

    return DosTree1HasTree2(pRoot1->m_pLeft,pRoot2->m_pLeft) &&
    DosTree1HasTree2(pRoot1->m_pRight,pRoot2->m_pRight);

}
bool HasSubtree(BinaryTreeNode *pRoot1,BinaryTreeNode *pRoot2)
{
    bool result=false;
    if(pRoot1!=NULL && pRoot2!=NULL)
    {
        if(pRoot1->m_value == pRoot2->m_value)
        {
            result=DosTree1HasTree2(pRoot1,pRoot2);
        }

        if(!result)
        {
            result=HasSubtree(pRoot1->m_pLeft,pRoot2);
        }
        if(!result)
        {
            result=HasSubtree(pRoot1->m_pRight,pRoot2);
        }

    }

    return result;

}

/*
    二叉树的镜像
*/

void MirrorRecursively(BinaryTreeNode *pRoot)
{
    if(pRoot==NULL)
    {
        return ;
    }
    if(pRoot->m_pLeft==NULL && pRoot->m_pRight==NULL)
    {
        return ;
    }

    BinaryTreeNode *temp=pRoot->m_pLeft;
    pRoot->m_pLeft=pRoot->m_pRight;
    pRoot->m_pRight=temp;

    if(pRoot->m_pLeft)
    {
        MirrorRecursively(pRoot->m_pLeft);
    }

    if(pRoot->m_pRight)
    {
        MirrorRecursively(pRoot->m_pRight);
    }

}

/*
    题目:求二叉树中和为某一值得路径
    输入一个二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 

*/

void FindPath(BinaryTreeNode *pRoot,int expectedSum,std::vector<int> &path,int currentSum)
{
    currentSum+=pRoot->m_value;
    path.push_back(pRoot->m_value);
    bool isLeaf=pRoot->m_pLeft==NULL &pRoot->m_pRight==NULL;

    if(currentSum== expectedSum && isLeaf)
    {
        printf("\nLJ is found!\n");
        std::vector<int>::iterator iter=path.begin();
        for(;iter!=path.end();++iter)
        {
            printf("%d\t",*iter);
        }

    }

     if(pRoot->m_pLeft!=NULL && currentSum<expectedSum)
    {
         FindPath(pRoot->m_pLeft,expectedSum,path,currentSum);
    }

    if(pRoot->m_pRight!=NULL && currentSum<expectedSum)
    {
         FindPath(pRoot->m_pRight,expectedSum,path,currentSum);
    }

    path.pop_back();

}
void FindPath(BinaryTreeNode *pRoot,int expectedSum)
{
    if(pRoot==NULL)
    {
        return ;
    }
    std::vector<int> path;
    int currentSum=0;
    FindPath(pRoot,expectedSum,path,currentSum);

}

int main()
{
    int a[8]={1,2,4,7,3,14,6,8};
    int b[8]={4,7,2,1,14,3,8,6};

    BinaryTreeNode *treeNode=ConstructTree(a,b,8);
    if(treeNode!=NULL)
    {
        preorderTraverse(treeNode);
        putchar(‘\n‘);
        inorderTraverse(treeNode);
        putchar(‘\n‘);
        postorderTraverse(treeNode);
    }

    printf("\nBFS: ");
    BFS(treeNode);
    printf("\nDFS: ");
    DFS(treeNode);
    FindPath(treeNode,18);
    printf("\n");
    system("pause  ");

    return 0;
}

时间: 2024-08-01 12:57:06

面试之常用算法总结的相关文章

程序员如何快速准备面试中的算法

前言 我决定写篇短文,即为此文.之所以要写这篇文章,缘于微博上常有朋友询问,要毕业找工作了,如何备战算法.尽管在微博上简单梳理过,如下图所示: 但因字数限制,特撰此文着重阐述下:程序员如何快速准备面试中的算法,顺便推荐一些相关的书籍或资料. 备战面试中算法的五个步骤 总体来说,备战面试中的算法,分为五个步骤,如下: 1.首选你得确保自己已经掌握好一门编程语言 如果是C的话,推荐Dennis M. Ritchie & Brian W. Kernighan著的<C程序设计语言>,和<

机器学习&amp;数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)

http://www.cnblogs.com/tornadomeet/p/3395593.html 机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 前言: 找工作时(IT行业),除了常见的软件开发以外,机器学习岗位也可以当作是一个选择,不少计算机方向的研究生都会接触这个,如果你的研究方向是机器学习/数据挖掘之类,且又对其非常感兴趣的话,可以考虑考虑该岗位,毕竟在机器智能没达到人类水平之前,机器学习可以作为一种重要手段,而随着科技的不断发展,相信这方面的人才需求也会越来越大.

【常用算法思路分析系列】排序高频题集

最近在牛客上整理常用的一些算法思路,[常用算法思路分析系列]主要是针对一些高频算法笔试.面试题目的解题思路进行总结,大部分也给出了具体的代码实现,本篇文章是对排序相关题目的思路分析. 1.简单分类 首先对一些常用算法按空间复杂度进行分类如下: O(1): 冒泡排序.选择排序.插入排序.希尔排序.堆排序 O(logN)~O(N): 快速排序 O(N): 归并排序 O(M): 计数排序.基数排序 2.对一个基本有序的有序的数组排序,选择哪种排序算法? 基本有序:指如果把数组排好序的话,每个元素移动的

程序员如何快速准备面试中的算法 - 结构之法

准备面试.学习算法,特别推荐最新出版的我的新书<编程之法:面试和算法心得>,已经上架京东等各大网店 前言 我决定写篇短文,即为此文.之所以要写这篇文章,缘于微博上常有朋友询问,要毕业找工作了,如何备战算法.尽管在微博上简单梳理过,如下图所示: 但因字数限制,许多问题无法一次性说清楚,故特撰此文着重阐述下:程序员如何快速准备面试中的算法,继而推荐一些相关的书籍或资料.顺便也供节后跳槽.3月春季招聘小高潮.及6月毕业找工作的朋友参考. 备战面试中算法的五个步骤 对于立志进一线互联网公司,同时不满足

面试10大算法汇总

英文版 以下从Java角度解释面试常见的算法和数据结构:字符串,链表,树,图,排序,递归 vs. 迭代,动态规划,位操作,概率问题,排列组合,以及一些需要寻找规律的题目. 1. 字符串和数组 字符串和数组是最常见的面试题目类型,应当分配最大的时间.关于字符串,首先需要注意的是和C++不同,Java字符串不是char数组.没有IDE代码自动补全功能,应该记住下面的这些常用的方法. toCharArray() //获得字符串对应的char数组 Arrays.sort() //数组排序 Arrays.

五大常用算法

http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741370.html 分治算法 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)-- 任何一个可以用计

推荐系统中常用算法 以及优点缺点对比

推荐系统中常用算法 以及优点缺点对比 在 推荐系统简介中,我们给出了推荐系统的一般框架.很明显,推荐方法是整个推荐系统中最核心.最关键的部分,很大程度上决定了推荐系统性能的优劣.目前,主要的推荐方法包括:基于内容推荐.协同过滤推荐.基于关联规则推荐.基于效用推荐.基于知识推荐和组合推荐. 一.基于内容推荐 基于内容的推荐(Content-based Recommendation)是信息过滤技术的延续与发展,它是建立在项目的内容信息上作出推荐的,而不需要依据用户对项目的评价意见,更多地需要用机 器

(转)常用算法(Algorithm)的用法介绍

2算法部分主要由头文件<algorithm>,<numeric>和<functional>组成. 2<algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较.交换.查找.遍历操作.复制.修改.反转.排序.合并等等. 2<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作. 2<functional>中则定义了一些模板类,用以声明函数对象. 2STL提供

[转]五大常用算法:分治、动态规划、贪心、回溯和分支界定

Referred from http://blog.csdn.net/yapian8/article/details/28240973 分治算法 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求