劍指offer-算法和數據結構:查找和排序

和數據結構一樣,算法的面試題也備受面試官的青睞,其中排序和查找是面試是考察算法的重點。
在準備面試的時候應該重點掌握二分查找、歸併排序和快速排序,做到能隨時正確、完整地寫出它們的代碼。

查找和排序都是在程序設計中常用到的算法。查找相對而言較爲簡單,不外乎順序查找、二分查找、哈希表查找和二叉排序樹查找。在面試的時候,不管用循環還是用遞歸,面試官都期待應聘者能夠寫出完整正確的二分查找代碼。。。

提示:如果面試題是要求在排序的數組(或者部分排序的數組)中查找一個數字或者統計某個數字出現的次數,都可以嘗試用二分查找算法。

哈希表和二叉排序樹查找的重點在於考查對應的數據結構而不是算法。哈希表最主要的優點是我們利用它能夠在O(1)時間查找某一元素,是效率最高的查找方式。但其缺點是需要額外的空間來實現哈希表。
與二叉排序樹查找算法對應的數據結構是二叉搜索樹。

排序比查找要複雜一些。面試官會經常要求應聘者比較插入排序、冒泡排序、歸併排序、快速排序等不同算法的優劣。強烈建議應聘者在準備面試的時候,對各種排序算法的特點記牢,能夠從額外空間消耗、平均時間複雜度和最差時間複雜度等方面去比較它們的優缺點。需要強調的是,很多公司的面試官喜歡在面試環節中要求應聘者寫出快速排序的代碼

實現快速排序算法的關鍵在於先在數組中選擇一個數字,接下來把數組中的數字分爲兩部分,比選擇的數字小的數字移到數組的左邊,比選擇的數字大的數字移到數組的右邊。
下面的函數可以實現此項功能

int Partition( int data[], int length, int start, int end )
{
    if( data==NULL || length <= 0 || start<0 || end>=length )
        throw new std::exception("Invalid Parameters");
    int index = RandomInRange( start, end );  //生成一個在start和end之間的隨機數
    Swap( &data[index], &data[end] ); //交換兩個數字,將生成的樞軸值與最後的位置值交換

//將小於樞軸值的數字,放到樞軸位置的左側;大於樞軸值的數字,放到樞軸位置的右側 
    int small = start - 1;
    for( index = start; index < end; ++index )
    {
        if( data[index] < data[end] )
        {
            ++small;
            if( small != index )
                Swap( &data[index], &data[small] );
        }
    }

    ++small;
    Swap( &data[small], &data[end] );

    return small;
}


void QuickSort( int data[], int length, int start, int end )
{
    if( start==end )
        return;

    int index = Partition( data, length, start, end );
    if( index > start )
        QuickSort( data, length, start, index-1 );
    if( index < end )
        QuickSort( data, length, index+1, end );
}

不同的排序算法使用的場合也不盡相同。快速排序雖然總體的平均效率是最好的,但也不是任何時候都是最優的算法。比如,數組本身已經排好序了,而每一輪排序的時候都是以最後一個數字作爲比較的標準,此時快速排序額效率只有O(n^2)。因此在這種場合快速排序就不是最優的算法。在面試的時候,如果面試官要求實現一個排序算法,那麼應聘者一定要問清楚這個排序應用的環境是什麼、有哪些約束條件,在得到足夠多的信息之後再選擇最合適的排序算法。

面試官:請實現一個排序算法,要求時間效率O(n)
應聘者:對什麼數字進行排序,有多少數字?
面試官:我們相對公司所有員工的年齡排序。公司有幾萬名員工。
應聘者:也就是說數字的大小是在一個較小的範圍之內的,對吧?
面試官:恩,是的
應聘者:可以使用輔助空間嗎?
面試官:看你用多少輔助內存。只允許使用常量大小輔助空間,不得超過O(n)。

則,代碼如下

void SortAges( int ages[], int length )
{
    if( ages==NULL || length <= 0 )
        return ;
    const int oldestAge = 99;
    int timesofAge[ oldestAge + 1 ];

    for( int i=0; i<=oldestAge; ++i )
        timesofAge[i] = 0;
    for( int i=0; i<length; ++i )
    {
        int age = ages[i];
        if( age<0 || age > oldestAge )
            throw new std::exception("age out of range.");
        ++timesofAge[ age ];
    }

    int index =0;
    for( int i=0; i<=oldestAge; ++i )
    {
        for( int j =0; j<timesofAge[i]; ++j )
        {
            ages[ index ] = i;
            ++index;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章