第3章 数据结构与算法

1. memmove边界问题

void memmove_(char *pDst,const char* pSrc,size_t size){
    assert(pSrc!=NULL&&pDst!=NULL);
    const char* p;
    char*q;
    if(pSrc<pDst&&pSrc+size>pDst){
        p=pSrc+size-1;
        q=pDst+size-1;
        while(size--)
            *q--=*p--;
    }
    else{
        p=pSrc;
        q=pDst;
        while(size--)
            *q++=*p++;
    }                                                        
}

2. 出错处理方式

3. 字符串算法的实现

(1) strstr函数: 进行了比较好的判断, 主要是便于比较快的结束判断

char* strstr_(const char *str1,const char* str2){
    assert(str1!=NULL&&str2!=NULL);
    int len1=strlen(str1);
    int len2=strlen(str2);
    if(len2>len1)//如果str2的长度大于str1的长度, 直接可以返回NULL
        return NULL;
    while(*str1!='\0'){
        const char *p=str1;
        const char *q=str2;
        while(*q&&*p==*q)
            p++,q++;
        if(*q=='\0')
            return str1;
        str1++;
        len1--;
        if(len1<len2)//如果此时str1剩余的长度小于str2的话,这样就没有再继续查找的必要了
            return NULL;
    }
}

(2) strtok函数的实现

char *strtok_(char *str,const char *delim){
    char *p;
    static char *nexttoken;
    char map[32]={0};//map是一个位图,256位,用来记录delim中的字符(分隔符)
    do{ 
        map[*delim>>3]|=(1<<(*delim&7));//将分隔符对应的位置设置为1
    }while(*delim++);
    if(str)
        p=str;
    else 
        p=nexttoken;
//如果开始字符为分隔符, 略过
    while((map[*p>>3]&(1<<(*p&7)))&&*p)
        p++;
    str=p;
    while(*p){
        if(map[*p>>3]&(1<<(*p&7))){//如果*p为分隔符, 那么将这个位置设为’\0’, 这样就完成了一个单词的分割
            *p++='\0';
            break;
        }
        p++;
    }
    nexttoken=p;//用static变量记录下一个分隔开始的起点.
    if(str==p)
        return NULL;
    else 
        return str;

(3) 删除特定的字符数组

这儿同样是使用map位图来记录出现的字符

char *deleteChars(char *str, const char *chr){
    assert(str!=NULL);
    char map[32]={0};
    int i=0,j=0;
    while(*chr){
        map[*chr>>3]|=(1<<(*chr&7));
        chr++;
    }
    
    do{ 
        if(!(map[str[j]>>3]&(1<<(str[j]&7))))
            str[i++]=str[j];
    }   
    while(str[j++]!='\0');
    return str;
}  

(4) IP地址与无符号整型数的转换

unsigned int str2int(char *str,int n){
    unsigned int val=0;
    int i;
    for(i=0;i<n;i++){
        val=val*10+(str[i]-'0');
    }
    return val;
}
unsigned int ip2int(char* ip,int* flag){
    char *p1=ip;
    int len=0;
    char pos[3];
    int count=0;
    unsigned int s1,s2,s3,s4;
    while(*p1!='\0'){
        if(!(*p1>='0'&&*p1<='9'||*p1=='.')) {
            printf("Invalid char:%c\n",*p1);
//            exit(-1);
            *flag=-1;
            return -1;
        }
        if(*p1=='.')
            pos[count++]=len;
        p1++;
        len++;
    }
    if(count!=3) {
        printf("Not enough \'.\'\n");
        *flag=-2;
        return -2;
//        exit(-2);
    }
    printf("pos:%d %d %d\n",pos[0],pos[1],pos[2]);
    if(pos[0]==0||pos[2]==len-1||pos[1]-pos[0]==1||pos[2]-pos[1]==1) {
        printf("Invalid Format:缺少一个IP段\n");
        *flag=-3;
        return -3;
//        exit(-3);
    }
    if(pos[0]>3||pos[1]-pos[0]>4||pos[2]-pos[1]>4||len-pos[2]>4){
        printf("Invalid Format:IP段太长\n");
        *flag=-4;
        return -4;
//        exit(-4);
    }
    s1=str2int(ip,pos[0]);
    s2=str2int(ip+pos[0]+1,pos[1]-pos[0]-1);
    s3=str2int(ip+pos[1]+1,pos[2]-pos[1]-1);
    s4=str2int(ip+pos[2]+1,len-pos[2]-1);
    printf("%x.%x.%x.%x -> ",s1,s2,s3,s4);
    if(!(s1>=0&&s1<=255&&
        s2>=0&&s2<=255&&
        s3>=0&&s3<=255&&
        s4>=0&&s4<=255)) {
        printf("Invalid Format:IP段超出范围\n");
        *flag=-5;
        return -5;
//        exit(-5);
    }
    *flag=1;
    return s1<<24|s2<<16|s3<<8|s4;
}
void ip_test(){
    char *ip[]={"0.0.0.0","211.211.22.33",
        ".","..","...","......","211...","211.22.0.0",
        "211.22..0","211.22.ab.33",".22.33.55"
    };
    int len=sizeof(ip)/sizeof(ip[0]);
    int i;
    for(i=0;i<len;i++){
        int flag;
        unsigned int val;
        printf("%s\n",ip[i]);
        val=ip2int(ip[i],&flag);
        printf("%#x\n",val);
        printf("flag=%d\n");
        if(flag<0){
            printf("Invalid Format\n");
        }
        printf("==================\n");
    }

}

(5)正则表达式匹配问题

int PatternMatch(const char* pat,const char*str){
     const char *s=NULL;
     const char *p=NULL;
     int star=0,bBreak=0;
     do{
         bBreak=0;
         for(s=str,p=pat;*s;++s,++p){
             switch(*p){
                 case '?':
                     break;
                 case '*':
                     star=1;
                     str=s;
                     pat=p;
                     if(!*++pat)
                         return 1;
                     bBreak=1;
                     break;
                 default:
                     if(*s!=*p){
                         if(!star)
                             return 0;
                         str++;
                         bBreak=1;
                     }
                     break;
             }           
             if(bBreak)      
                 break;  
         }               
         if(!bBreak){
             if(*p=='*')
                 ++p;    
             return !*p;     
         }       
         
     }while(1);
 }           
void PatternMatch_test(){
    char *pat="hell*world*!";
    char *str="hellfasdfdworldfadsf!";
    int b=PatternMatch(pat,str);
    printf("%d\n",b);
}

4. 判断单向链表中是否存在循环?

5. 树的遍历算法

使用两种方式:递归和非递归的方式

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#define print_arr(a,n) for(int i=0;i<n;i++)\
                                 printf("%d ",a[i]);\
printf("\n")
using namespace std;
struct node{
    node():left(0),right(0){}
    node(int d):data(d),left(0),right(0){}
    int data;
    node* left;
    node* right;
};
//node *tree_create(int *first,int* end){
//    if(first!=end){
//    node *root=new node;
//    root->data=*first++;
//    node* p=root;
//    while(first!=end){
//        node *q1=new node;
//        q1->data=*first++;
//        p->left=q1;
//        if(first!=end){
//            node *q2=new node;
//            q2->data=*first++;
//            p->right=q2;
//        }
//    }
//    }
//}
node *make_tree(node*root,int l,int r){
    node* p=new node(l);
    root->left=p;
    p=new node(r);
    root->right=p;
    return root;
}
node *make_tree(node*root,int l,bool flag=true){
    node* p=new node(l);
    if(flag)
        root->left=p;
    else
        root->right=p;
    return root;
}
node *free_tree(node *root){
    if(root!=0){
        free_tree(root->left);
        free_tree(root->right);
    }
}
//递归的前序遍历
void preorder(node *root){
    if(root){
        cout<<root->data<<' ';
        preorder(root->left);
        preorder(root->right);
    }
}
//使用栈来实现非递归的前序遍历
void preorder_(node *root){
    if(!root)
        return;
    stack<node*> st;
    st.push(root);
    node* p;
    while(!st.empty()){
        p=st.top();
        st.pop();
        cout<<p->data<<' ';
        if(p->right!=0)//将左子树压入栈
            st.push(p->right);
        if(p->left!=0)//将右子树压入栈
            st.push(p->left);
    }
}
//递归方式的中序遍历
void inorder(node *root){
    if(root){
        inorder(root->left);
        cout<<root->data<<' ';
        inorder(root->right);
    }
}
//同样使用栈来实现非递归的中序遍历
void inorder_(node *root){
    if(!root)
        return;
    stack<node*> st;
    node *p=root;
    do{
        //先将左子树不断的入栈
        while(p!=0){
            st.push(p);
            p=p->left;
        }
        //访问节点的值,然后再转向处理右子树
        if(!st.empty()){
            p=st.top();
            st.pop();
            cout<<p->data<<' ';
            p=p->right;
        }
    }while(p!=0||!st.empty());
}
//递归方式的后序遍历
void postorder(node *root){
    if(root){
        postorder(root->left);
        postorder(root->right);
        cout<<root->data<<' ';
    }
}//这是一种比较好的方式来实现后序遍历的

void postorder(Node* root){
    stack<Node*> st;
    Node* p=root,*visited=0;
    while(p!=0||!st.empty()){
        while(p!=0){
            st.push(p);
            p=p->left;
        }
        p=st.top();
        if(p->right==0||visited==p->right){
            cout<<(int)p->data<<' ';
            st.pop();
            visited=p;
            p=0;
        }
        else{
            p=p->right;
        }   
    }       
    cout<<endl;
}      

//使用栈来实现非递归的后序遍历
void postorder_(node *root){
    if(!root)
        return;
    stack<node*> st;
    stack<bool> tag;//用来区分左右子树,false表示左子树,true表示右子树
    node *p=root;
    do{
        while(p!=0){
            st.push(p);
            tag.push(false);
            p=p->left;
        }
        if(!st.empty()){
            p=st.top();
            if(tag.top()){//如果是右子树就输出节点值
                st.pop();
                tag.pop();
                cout<<p->data<<' ';
                p=0;
            }
            else{//当前是节点的左子树,需要将其右子树进行处理(入栈)
                p=p->right;
                tag.top()=true;
            }
        }
    }while(p!=0||!st.empty());
}
//分层遍历,很自然的使用队列
void levelorder(node *root){
    if(!root)
        return;
    queue<node*> q;
    node *p=root;
    q.push(p);
    while(!q.empty()){
        p=q.front();
        q.pop();
        cout<<p->data<<' ';
        if(p->left!=0)
            q.push(p->left);
        if(p->right!=0)
            q.push(p->right);
    }
}
void in_post_pre(int* in,int *post,int *pre,int n){

}

int main(){
    node *root=new node(20);
    make_tree(root,10,30);
    node *p=root->left;
    make_tree(p,15,14);
    p=p->right;
    make_tree(p,28,false);
    p=root->right;
    make_tree(p,29,41);

//    preorder(root);    cout<<endl;
//    preorder_(root);    cout<<endl;
//    inorder(root);cout<<endl;
//    inorder_(root);cout<<endl;
//    postorder(root);cout<<endl;
//    postorder_(root);cout<<endl;
    levelorder(root);cout<<endl;
    
    free_tree(root);
}

6. 平衡二叉排序树

7. 常用的查找方法

主要包括折半查找,二叉排序树查找和Hash表查找.

(1). 折半查找复杂度是O(logn), 需要满足两个条件: 元素必须是连续存储并且是有序的.

(2). 二叉排序树查找.

(3) hash表查找

问题1: 查找兄弟单词

问题2: 查找字符串中第一个不重复的字符

问题3: 统计最热门的10个查询串

8. 树中某些节点的公共祖先问题

问题1: 求出从根节点到给定节点的路径.

代码如下:

void find_path(node*root,node* p){
    node* stk[100],*s;
    int tag[100],i,top=-1;
    s=root;
    do{
        while(s!=0){//不断的将左子树进行压栈
            top++;
            stk[top]=s;
            tag[top]=0;
            s=s->left;
        }   
        if(top>-1){
            s=stk[top];
            if(tag[top]==1){//右子树遍历完毕,开始遍历根节点
                if(s==p) {
                    for(i=0;i<=top;i++){
                        printf("%d ",stk[i]->data);
                    }
                    break;
                }   
                else    
                    top--;
            }       
            else{//还没有遍历右子树,开始遍历右子树
                s=s->right;
                tag[top]=1;
            }                                                   
        }   
    }while(s!=0||top>-1);

问题2: 查找两个节点的公共祖先

利用上面的查找到根节点路径的方法就可以了.

问题3: 找出二叉搜索树上两个节点的公共祖先.

公共祖先节点的值肯定位于这两个值之间.

10. 字典树(trie树)

字典树可以解决下面一些问题:

问题1: 纠错问题

问题2: 查找公共的url

11. 递归在树中的应用

代码如下:

int like(node* root1,node* root2){
    if(root1==0&&root2==0)
        return 1;
    else if(root1==0||root2==0)
        return 0;
    else
        return like(root1->left,root2->left)&&
            like(root1->right,root2->right);
}                                         

node* copy_tree(node*root){
     node*root2;
     if(root!=0){
         root2=(node*)malloc(sizeof(node));
         root2->data=root->data;
         root2->left=copy_tree(root->left);
         root2->right=copy_tree(root->right);
         return root2;
     }
     else
         return 0;                               
 }

void maxminleaf(node*root,int *m,int *n){
    int m1,m2,n1,n2;
    if(root=0){
        *m=0;
        *n=0;
    }  
    else{
        maxminleaf(root->left,&m1,&n1);
        maxminleaf(root->right,&m2,&n2);
        m=max(*m1,*m2)+1;
        n=min(*n1,*n2)+1;
    }
}

node* swap_tree(node*root){
     if(root=0)
         return 0;
     else{
         node* root2=(node*)malloc(sizeof(node));
         root2->data=root->data;
         root2->left=swap_tree(root->right);
         root2->right=swap_tree(root->left);
         return root2;
     }
 }                                        

int leaf_cnt(node* root){
    if(root=0)
        return 0;
    if(root->left==0&&root->right==0)
        return 1;
    return leaf_cnt(root->left)+leaf_cnt(root->right);      
}

转载于:https://www.cnblogs.com/xkfz007/archive/2012/10/11/2720607.html

程序员求职成功路(2) - 第3章 数据结构与算法相关推荐

  1. GitHub超4.4k星:程序员求职,一个算法模板就够了

    来源:新智元 本文约1800字,建议阅读5分钟 本文为你介绍程序员求职中科学的.高效的刷题方式. [ 导读 ] 近日,GitHub上一个名为"算法模板"的项目引发热议,获得了超4. ...

  2. 程序员编程艺术:第三章续、Top K算法问题的实现

    程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha.     致谢:微软100题实现组,狂想曲创作组.     时间:2011年05月08日    ...

  3. 程序员编程艺术:第五章、寻找满足和为定值的两个或多个数

    程序员编程艺术:第五章.寻找和为定值的两个或多个数 作者:July,yansha,zhouzhenren.     致谢:微软100题实现组,编程艺术室.     微博:http://weibo.co ...

  4. 个人经历:谈一谈的程序员求职途径

    个人经历:谈一谈的程序员求职途径 互联网招聘网站的确是五花八门,种类繁多,在投递简历,接听面试电话的过程中,要擦亮眼睛,慎重选择和沟通.我是去年跳槽的,下面就来说说我投递简历的过程,希望对大家有所帮助 ...

  5. 程序员求职简历,项目经验怎么写?免费修改简历并提供简历模板

    我是一个典型的互联网公司程序员,在BAT有超过10年的工作经验,面试超过200个程序员.也见过无数的程序员简历,包括很多优秀的程序员简历,看了可以让人眼前一亮,优美简洁的简历模板,项目经验工作重点突出 ...

  6. 计算机程序员求职信英语作文,英文程序员求职信

    程序员是从事程序开发.维护的专业人员,工作离不开英文.那么你知道英文程序员求职信是怎么写的吗?下面学习啦小编整理了英文程序员求职信,供你参考. 英文程序员求职信范文一 dear mr. arline, ...

  7. 研发程序员求职简历表-Word简历可编辑下载

    研发程序员求职简历表(word格式),制作一份精美简历能让你与众不同,帮助求职者在求职面试过程中脱颖而出,给HR留下好的第一印象高分,提升求职成功率,争取高薪机会. 简历模板:word格式(可任意便捷 ...

  8. .net程序员求职简历

    .net程序员求职简历 个人概况 姓名 齐志超 学历 专科 毕业学校 河北软件职业技术学院 专业 软件开发与设计 手机 18730269286 年龄 22 性别 男 现居住地 北京 电子邮件 qzc9 ...

  9. C/C++程序员求职面试指导

    引言 本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵.文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见. 许多面试题看似简单,却需要深厚的基本功才 ...

最新文章

  1. thinkphp mysql 密码加密_thinkphp框架实现mysql读写分离
  2. oracle 优化器 失效,oracle 优化器 不走索引原因
  3. 智源青年科学家林乾:揭开人工智能的黑匣,从解答最基本的问题开始
  4. 性能测试应该怎么做?
  5. 用TWaver加载大型游戏场景一例
  6. oracle中如何创建dblink
  7. 中国风喜庆传统新年元旦海报PSD分层模板
  8. jieba源码分析(二)
  9. 编程之美——3.1字符串移位包含问题
  10. 字符串题目 --- 递归和动态规划
  11. JAVA教程下载-JAVA学习视频教程网盘分享
  12. 苹果蓝牙耳机怎么接电话_拆解报告:高仿苹果AirPods真无线蓝牙耳机
  13. 烽火计划-2020年夏-期末总结
  14. 月薪过万的java程序员需要什么能力_什么样能力的Java程序员月薪过万
  15. SQL中如何处理除数为0的情况?
  16. 关于安装KVM后不会出现/dev/kvm设备的问题
  17. 极坐标弧长积分公式简单理解 极坐标求面积的公式,dθ 弧长积分公式,rd​原理; 极坐标弧积分
  18. 麦田里的守望者——读后理解
  19. 链接服务器“(null)“的 OLE DB 访问接口 “SQLNCLI10“ 返回了消息 “客户端无法建立
  20. Wear OS手表应用开发教程之-创建应用

热门文章

  1. swaggerui api.docs
  2. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。...
  3. 微博达人硅谷之歌:Testin云測移动搜索性能測试非常是让人信服
  4. 主成分分析(PCA)原理及R语言实现
  5. 快速更换一个国内的yum源
  6. 关于visualizer的setEnabled()方法何时进行设置成false?
  7. [Ubuntu 12.10] Openstack 多节点安装--前期准备网络拓扑
  8. 全球三大BCH(比特币现金)城市,有你想去的吗
  9. Bitcoin Unlimited客户端发布新版本,删除了BSV协议功能
  10. Delegate,Action,Func,匿名方法,匿名委托,事件