C++ 经典算法 面试绝杀

1.链表逆序

2.链表合并

3.一棵树是否某条路径结点之和等于给定值。并描述算法复杂度

4.你熟悉的排序算法并描述算法复杂度。

         快速排序

         归并排序

         堆排序

         选择排序

         插入排序

        冒泡排序

        折半插入排序

以下代码都能成功通过。


1.链表逆序


#include <iostream>
using namespace std;

struct node
{
    int value;
    node * next;
};

node* make_link(void);
node* reverse(node*);
void display(node *);

int main()
{
    node *head=make_link();
    display(head);
    head=reverse(head);
    display(head);

    return 0;
}

node* make_link(void)
{
    node *head=new node();
    node *cur=head;
    for(int i=0;i<10;i++)
    {
        cur->value=rand()%10;
        cur->next=new node();
        cur=cur->next;
    }

    return head;
}

node* reverse(node *head)
{
    node *pre,*post,*cur;
    if(!head && !head->next)
        return head;
    pre=head;
    cur=pre->next;
    while(cur)
    {
        post=cur->next;
        cur->next=pre;
        pre=cur;
        cur=post;
    }
    head->next=NULL;
    return pre;
}

void display(node * head)
{
    node * cur=head;
    while(cur)
    {
        cout<<cur->value<<" ";
        cur=cur->next;
    }
    cout<<endl;
}




2.链表合并
#include <iostream>

using namespace std;

struct node
{
    int value;
    node *next;
};

node *make_list(void);
void display(node *);
void sort(node *);
node *merge(node *,node *);

int main()
{
    node *node1=make_list();
    display(node1);
    sort(node1);

    node *node2=make_list();
    display(node2);
    sort(node2);

    node *mnode=merge(node1,node2);
     display(mnode);

    return 0;
}


node *make_list(void)
{
    node *head=new node();
    node *cur=head;
    for(int i=0;i<10;i++)
    {
        cur->value=rand()%10;
        cur->next=new node();
        cur=cur->next;
    }

    return head;
}

void display(node *head)
{
    node *cur=head;
    while(cur)
    {
        cout<<cur->value<<" ";
        cur=cur->next;
    }
    cout<<endl;
}


void sort(node *head)
{
    node *cur=head;
    while(cur)
    {
        node *min=cur;
        node *cur2=cur->next;
        while(cur2)
        {
            if(cur2->value < min->value)
                min=cur2;
            cur2=cur2->next;
        }

        int temp=cur->value;
        cur->value=min->value;
        min->value=temp;
        cur=cur->next;
    }
}

node *merge(node *h1,node *h2)
{
    node *mcur=new node();
    node *cur1=h1;
    node *cur2=h2;
    while(cur1&&cur2)
    {
        if(cur1->value < cur2->value)
        {
            mcur->next=cur1;
            mcur=mcur->next;
            cur1=cur1->next;
        }
        else
        {
            mcur->next=cur2;
            mcur=mcur->next;
            cur2=cur2->next;
        }
    }
    if(cur1)
        mcur->next=cur1;
    else
        mcur->next=cur2;
    return h1->value < h2->value ? h1:h2;
}



3.一棵树是否某条路径结点之和等于给定值。并描述算法复杂度
#include <iostream>
using namespace std;

struct node
{
    int value;
    node *left;
    node *right;
};

node * build_tree(void);
bool find(node *,int);

int main()
{
    node *tree=build_tree();
    int t;
    cout<<"Enter your number:";
    cin>>t;
    cout<<endl;
    cout<<find(tree,t)<<endl;
}

node *build_tree()
{
    int a;
    cin>>a;
    if(a == 0)
        return NULL;
    node *root=new node();
    root->value=a;
    root->left=build_tree();
    root->right=build_tree();

    cout<<"build tree success"<<endl;
    return root;
}

bool find(node *root,int v)
{
    if(!root)
        return false;
    if(root->value == v)
        return true;
    else find(root->left,v-root->value) || find(root->right,v-root->value);
}



4.你熟悉的排序算法并描述算法复杂度。
快速排序

#include <iostream>
using namespace std;

int partition(int a[],int low,int high)
{
    int key=a[low]; //用子表的第一个记录作杻轴记录
    while(low < high)   //从表的两端交替地向中间扫描
    {
        while(low < high && a[high] >= key)
            --high;
        {                  //将比杻轴记录小的记录交换到低端
            int temp=a[low];
            a[low]=a[high];
            a[high]=temp;
        }

        while(low < high && a[low] <= key)
            ++low;
        {                 //将比杻轴记录大的记录交换到低端
            int temp=a[low];
            a[low]=a[high];
            a[high]=temp;
        }
    }
    return low;   //返回杻轴所在的位置
}

void qsort(int a[],int b,int e)
{
    if(b < e)
    {
        int m=partition(a,b,e);
        qsort(a,b,m-1);
        qsort(a,m+1,e);
    }
}

int main()
{
    int a[]={2,3,7,8,3,5};
    qsort(a,0,5);
    for(int i=0;i<6;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}



归并排序
#include <iostream>
using namespace std;

void display(int a[],int size)
{
    for(int i=0;i<size;i++)
        cout<<a[i]<<" ";
    cout<<endl;
}

void mmerge(int *a,int low,int middle ,int high )
{
    int fronArray[100],postArray[100];
    int front=middle-low+1;
    int post=high-middle;
    for(int i=0;i<front;i++)
        fronArray[i]=a[low+i];

    for(int j=0;j<post;j++)
        postArray[j]=a[middle+j+1];

    fronArray[front]=9999; //哨兵
    postArray[post]=9999;

    int i=0,j=0;
    for(int k=low;k<=high;k++)
    {
        if(fronArray[i]<postArray[j])
            a[k]=fronArray[i++];
        else
            a[k]=postArray[j++];
    }
}

void merge_sort(int *a,int low,int high)
{
    if(low<high)
    {
        int middle=(low+high)/2;
        merge_sort(a,low,middle);
        merge_sort(a,middle+1,high);
        mmerge(a,low,middle,high);
    }
}

int main()
{
    int a[]={9,3,5,7,6,8,10,22,21,34};
    display(a,10);
    merge_sort(a,0,9);
    display(a,10);

    return 0;
}



堆排序

/*
堆排序
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,
由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③ 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。
然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,
由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n- 2].keys≤R[n-1..n].keys,
同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
(2)大根堆排序算法的基本操作:
① 初始化操作:将R[1..n]构造为初始堆;
② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
注意:
①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。
堆排序和直接选择排序相反:在任何时刻,堆排序中无序区总是在有序区之前,
且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。
*/

#include <iostream>

using namespace std;

//生成大根堆
void HeapAdjust(int SortData[],int StartIndex, int Length)
{
    while(2*StartIndex+1 < Length)
    {
        int MaxChildrenIndex = 2*StartIndex+1 ;
        if(2*StartIndex+2 < Length )
        {
            //比较左子树和右子树,记录最大值的Index
            if(SortData[2*StartIndex+1]<SortData[2*StartIndex+2])
            {
                MaxChildrenIndex = 2*StartIndex+2;
            }
        }
        if(SortData[StartIndex] < SortData[MaxChildrenIndex])
        {
            //交换i与MinChildrenIndex的数据
            int tmpData =SortData[StartIndex];
            SortData[StartIndex] =SortData[MaxChildrenIndex];
            SortData[MaxChildrenIndex] =tmpData;
            //堆被破坏,需要重新调整
            StartIndex = MaxChildrenIndex ;
        }
        else
        {
            //比较左右孩子均大则堆未破坏,不再需要调整
            break;
        }
    }
}

//堆排序
void HeapSortData(int SortData[], int Length)
{
    int i=0;

    //将Hr[0,Length-1]建成大根堆
    for (i=Length/2-1; i>=0; i--)
    {
        HeapAdjust(SortData, i, Length);
    }

    for (i=Length-1; i>0; i--)
    {
        //与最后一个记录交换
        int tmpData =SortData[0];
        SortData[0] =SortData[i];
        SortData[i] =tmpData;
        //将H.r[0..i]重新调整为大根堆
        HeapAdjust(SortData, 0, i);
    }
}

//TestCase
int main()
{
    int SortData[] ={12,36,24,85,47,30,53,91};

    HeapSortData(SortData, 8);

    for (int i=0; i<8; i++)
    {
        cout<<SortData[i]<<" ";
    }
    cout<<endl;

    return 0;
}



选择排序
//每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录
#include <iostream>
using namespace std;

void selectSort(int a[],int size)
{
    for(int i=0;i<size-1;i++)
    {
        int lowIndex =i;
        for(int j=size-1;j>i;j--)
            if(a[j]<a[lowIndex])
                lowIndex=j;
        int temp=a[i];
        a[i]=a[lowIndex];
        a[lowIndex]=temp;
    }
}

int main()
{
    int a[]={12,36,24,85,47,30,53,91};
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    selectSort(a,8);
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}


插入排序
//将一个记录插入到已经排好序的有序表中,从而得到一个新的 、记录数增1的有序表
#include <iostream>
using namespace std;

void insertSort(int a[],int size)
{
    for(int i=1;i<size;i++)
        for(int j=i;(j>0)&&(a[j]<a[j-1]);j--)
        {
            int temp=a[j];
            a[j]=a[j-1];
            a[j-1]=temp;
        }
}

int main()
{
    int a[]={12,36,24,85,47,30,53,91};
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    insertSort(a,8);
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}



冒泡排序
//在冒泡排序的过程中,关键字较小的记录好比水中的气泡逐趟向上漂浮,而关键字较大的记录好比石块往下沉,每一趟有一块“最大”的石头沉到水底。
#include <iostream>
using namespace std;

void busort(int a[],int size)
{
    for(int i=0;i<size-1;i++)
        for(int j=size-1;j>i;j--)
        if(a[j]<a[j-1])
        {
            int temp=a[j];
            a[j]=a[j-1];
            a[j-1]=temp;
        }
}

int main()
{
    int a[]={12,36,24,85,47,30,53,91};
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    busort(a,8);
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}



折半插入排序
#include <iostream>
using namespace std;

void BInsertSort(int a[],int size)
{
    for(int i=1;i<size;i++)
    {
        int temp=a[i];               //暂存a[i]
        int low=0;
        int high=i-1;
        while(low<=high)
        {
            int middle=(low+high)/2;
            if(temp<=a[middle])
                high=middle-1;
            else
                low=middle+1;
        }

        for(int j=i-1;j>=high+1;--j)   //记录后移
            a[j+1]=a[j];
        a[high+1]=temp;                //插入,注意没有补齐的地方要注意,不然是野指针指向莫名的值。
    }
}

int main()
{
    int a[]={12,36,24,53,53,30,53,91};
    for(int i=0;i<8;i++)
        cout<<a[i]<<" ";
    cout<<endl;

    BInsertSort(a,8);
    for(int i=0;i<8;i++)
         cout<<a[i]<<" ";
    cout<<endl;

    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值