美文网首页
面试常见的手撕代码--链表、排序、二分、二叉树

面试常见的手撕代码--链表、排序、二分、二叉树

作者: 葛城巧 | 来源:发表于2018-09-19 00:59 被阅读0次

由于找工作要恶补数据结构的基础,为了手撕代码方便,写了很多代码并测试。都是些找工作常考的,现在贴上来,不定期更新部分代码。

  • 含有链表反转,排序算法,查找算法和二叉树的遍历算法。
  • 都是常考的手撕代码,建议找工作的童鞋使劲背。
  • 里面每一段代码都是经过调试的。
  • IDE建议使用CLion,个人感觉比较好用,没有VS那么大,不想破解就下社区版,配置教程可以参考我另一篇文章Window10极简CLion配置教程

链表反转

1. 结点定义

struct node{
    int node_data;
    struct node* next;
    node(int x) : node_data(x){}
};

2. 递归版

node* In_reverseList(node* head){
    if(head!=NULL && head->next != NULL){
        // l是新链表头
        node* l = In_reverseList(head->next);
        head->next->next = head;
        head->next=NULL;
        return l;
    } else
        return head;
}

3. 非递归版

node* reverseList(node* head){
    if (head != NULL && head->next != NULL){
        node* p = head;
        node *q, *newNode=NULL;
        while (p!=NULL) {
            q = p->next;
            p->next=newNode;
            newNode=p;
            p=q;
        }
        return newNode;
    }
}

排序算法

1.冒泡排序法

// 冒泡排序
vector<int> bubblesort(vector<int> u_in)
{
    vector<int> unii = u_in;
    for (int i = 0; i < unii.size(); i++)
    {
        int tmp = 0;
        for (int j = i + 1; j < unii.size(); j++)
        {
            if (unii[i] > unii[j])
            {
                tmp = unii[i];
                unii[i] = unii[j];
                unii[j] = tmp;
            }
        }
    }
    return unii;
}

2.选择排序法

// 选择排序法
void selectsort(int *a, int n) {
    int min;
    for (int i = 0; i < n; i++) {
        min = i;
        for (int j = i + 1; j < n; j++) {
            if (a[min] > a[j]) {
                min = j;
            }
        }
        if (min != i) {
            int temp = a[i];
            a[i] = a[min];
            a[min] = temp;
        }
    }
}

3.快速排序法

// 快排,数组版
void quicksort(int *a, int left, int right)
{
    if (left >= right) return;
    int i = left;
    int j = right;
    int based = a[left];
    while (i < j) {
        while (i < j && a[j] >= based) j--;
        if (i < j) {
            a[i] = a[j];
            i++;
        }
        while (i < j && a[i] < based) i++;
        if (i < j) {
            a[j] = a[i];
            j--;
        }
        if (i >= j) break;
    }
    a[i] = based;
    quicksort(a, left, j - 1);
    quicksort(a, j + 1, right);
}

4.归并排序法

// 归并排序单元使用
void mergearr(int* a, int begin, int mid, int end, int *temp){
    int i=begin, j=mid+1;
    int m = mid, n = end;
    int k = 0;
    while (i <= m && j<= n){
        if (a[i]<a[j])
            temp[k++]=a[i++];
        else
            temp[k++]=a[j++];
    }
    while (i<=m)
        temp[k++]=a[i++];
    while (j<=n)
        temp[k++]=a[j++];
    for (i=0;i<k;i++){
        a[begin+i]=temp[i];
    }
}

// 归并排序算子
void _merge_sort(int* a, int begin, int end, int *temp){
    if(begin<end) {
        int mid = (begin + end) / 2;
        _merge_sort(a, begin, mid, temp);
        _merge_sort(a, mid + 1, end, temp);
        mergearr(a, begin, mid, end,temp);
    }
}

// 归并排序
int* MergeSort(int *a, int len){
    int *temp = new int[len];
    _merge_sort(a,0,len-1,temp);
    return temp;
}

查找算法

1.二分查找(递归版)

// 二分查找
int getkey (int* a, int key, int low, int high)
{
    int mid = (low+high)/2;
    if (low>high) return -1;
    if (a[mid]==key) return mid;
    else if (a[mid]<key)
        return getkey(a,key,mid+1,high);
    else
        return getkey(a,key,low,mid-1);
}
int main(){
    int a[8]={5,10,29,37,39,56,65,88};
    int key = 88;
    cout<<getkey(a,key,0,8);
    return 0;
}

二叉树遍历(非递归版)

由于递归版过于简单,一般来说面试是不会考的,所以只放非递归版。

  • 节点定义
// 二叉树节点
struct binode{
    int val;
    binode* left;
    binode* right;
    explicit binode(int v){
        val=v;
        left=nullptr;
        right=nullptr;
    }
    binode(int v, binode* l, binode* r){
        val=v;
        left=l;
        right=r;
    }
    void setlrnode( binode* l, binode* r){
        left=l;
        right=r;
    }
    void setlnode( binode* l){
        left=l;
    }
    void setrnode( binode* r){
        right=r;
    }
};

1.先序遍历

// 先序遍历
void preorder(binode* root){
    if (root==nullptr) return;
    binode *p=root;
    stack<binode*> s;
    while (p!=nullptr || !s.empty()){
        while (p!= nullptr){
            cout<<p->val;
            s.push(p);
            p=p->left;
        }
        if (!s.empty()){
            p=s.top();
            s.pop();
            p=p->right;
        }
    }
}

2.中序遍历

中序遍历就是先序遍历的cout放到if里面。

// 中序遍历
void midorder(binode* root){
    if (root==nullptr) return;
    binode *p=root;
    stack<binode*> s;
    while (p!=nullptr || !s.empty()){
        while (p!= nullptr){
            s.push(p);
            p=p->left;
        }
        if (!s.empty()){
            p=s.top();
            cout<<p->val;
            s.pop();
            p=p->right;
        }
    }
}

3.后序遍历

后续遍历很容易出问题,之前的写的会内存泄露,现在修改了。

// 后序遍历
void postorder(binode* root){
    if (root==nullptr) return;
    binode *p=root;
    stack<binode*> s;
    stack<binode*> t;
    while (p!=nullptr || !s.empty()){
        while (p!= nullptr){
            s.push(p);
            t.push(p);
            p=p->right;
        }
        if (!s.empty()){
            p=s.top();
            s.pop();
            p=p->left;
        }
    }
    while (!t.empty()) {
        p=t.top();
        t.pop();
        cout<<p->val;
    }
}

4.层序遍历

层序遍历即广度优先搜索,按照每一层的节点从左到右输出,代码非常简单,用于计算二叉树的高度(面试题,今天小米面试被问了,没想起来)

// 二叉树层序遍历
void layerorder(binode* root){
    if(root== nullptr)
        return;
    binode* p;
    queue<binode*> q;
    q.push(root);
    while (!q.empty()){
        p = q.front();
        q.pop();
        cout<<p->val;
        if(p->left!= nullptr){
            q.push(p->left);
        }
        if(p->right!= nullptr){
            q.push(p->right);
        }
    }
}

5.测试用例

// 二叉树测试
int main()
{
    /* 假设有二叉树
          1
         |  \
        2    3
       |  \
      4    5
     |  \
    6    7
  */
    binode* root = new binode(1);
    // 构造二叉树,这样写是为了MD可以正常显示
    binode nd1(2);
    binode nd2(3);
    binode nd3(4);
    binode nd4(5);
    binode nd5(6);
    binode nd6(7);
    root->setlrnode(&nd1,&nd2);
    nd1.setlrnode(&nd3,&nd4);
    nd3.setlrnode(&nd5,&nd6);
    // 遍历
    preorder(root);
    cout<<endl;
    midorder(root);
    cout<<endl;
    postorder(root);
    cout<<endl;
    layerorder(root);
    return 0;
}

测试结果如下:

测试结果图

不定期继续更新ing~

相关文章

  • 面试常见的手撕代码--链表、排序、二分、二叉树

    由于找工作要恶补数据结构的基础,为了手撕代码方便,写了很多代码并测试。都是些找工作常考的,现在贴上来,不定期更新部...

  • 手撕排序算法C++

    即将进入秋招阶段,面试手撕代码是常有的事情,所以呢,早点准备,以防万一。现场手撕代码,最常见的就是排序,今天先上来...

  • 常见算法

    单链表反转 冒泡排序 选择排序 插入排序 希尔排序 快速排序 归并排序 堆排序 二分查找 重建二叉树

  • 原生javascript实现简单的数据结构与算法

    最近面试被问到冒泡排序和快速排序,要求现场手撕代码。 一.冒泡排序 Chrome下的测试结果: 二.快速排序 找出...

  • 2020-10-28

    快排 链表反转 链表反转 二叉树非递归实现 按层排序 二叉树深度 合并有序数组 二分查找 有序数组 查找 楼梯问题

  • 常见算法

    算法:8种排序,二叉树,链表,图论,二分法,和诺发,排列组合,递归时间复杂度:。。。。 1 排序 1.1 选择排序...

  • 面试:查找旋转数组的最小数字

    在算法面试中,面试官总是喜欢围绕链表、排序、二叉树、二分查找来做文章,而大多数人都可以跟着专业的书籍来做到倒背如流...

  • 面试:Java 实现查找旋转数组的最小数字

    在算法面试中,面试官总是喜欢围绕链表、排序、二叉树、二分查找来做文章,而大多数人都可以跟着专业的书籍来做到倒背如流...

  • 双向链表的快速排序(swift版本)

    面试经常会被问到的单向链表的快速排序or双向链表的快速排序,现在用swift写了一个双向链表的快速排序,直接上代码...

  • 想去阿里——这是你必备的实力

    算法和数据结构数组、链表、二叉树、队列、栈的各种操作(性能,场景) 二分查找和各种变种的二分查找 各类排序算法以及...

网友评论

      本文标题:面试常见的手撕代码--链表、排序、二分、二叉树

      本文链接:https://www.haomeiwen.com/subject/bfcbnftx.html