• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

            [算法問題]尋找一個序列中第n大的元素

            問題描述:給定一個序列,以及指定這個序列的一個范圍,尋找這個范圍之內第n大的元素,如果n大于這個范圍之內的元素數量那么就返回-1.

            這是快速排序算法中partiton算法的一個應用,不斷的分割序列,如果分割的位置正好是要找的位置,那么返回結果,否則視情況在前半部分和后半部分繼續查找,當然這個時候n值也要相應的變化了~~

            /* *******************************************************************
            ????created:????2006/07/04
            ????filename:?????nthElement.cpp
            ????author:????????李創
            ????????????????
            http://www.shnenglu.com/converse/

            ????purpose:????得到一個序列某個范圍以內的第n個元素的算法演示
            ????????????????提供了這個算法的遞歸和非遞歸的實現算法
            ????????????????同時為了測試之用提供了堆算法,用于在找到第N個元素之后
            ????????????????和排序之后的數組對應位置元素進行比較以測試代碼是否正確
            ********************************************************************
            */


            #include?
            < stdio.h >
            #include?
            < stdlib.h >
            #include?
            < time.h >

            // ?交換元素
            void ?Swap( int ? * a,? int ? * b)
            {
            ????
            int ?temp;

            ????temp?
            = ? * a;
            ????
            * a??? = ? * b;
            ????
            * b??? = ?temp;
            }


            // ?打印數組元素
            void ?DisplayArray( int ?array[],? int ?length)
            {
            ????
            int ?i;

            ????
            for ?(i? = ? 0 ;?i? < ?length;?i ++ )
            ????
            {
            ????????printf(
            " array[%d]?=?%d\n " ,?i,?array[i]);
            ????}

            }


            // ?隨機創建一個數組
            void ?CreateNewArray( int ?array[],? int ?length)
            {
            ????
            for ?( int ?i? = ? 0 ;?i? < ?length;?i ++ )
            ????
            {
            ????????array[i]?
            = ?rand()? % ? 256 ;
            ????}

            }


            // ?對一個給定范圍的子序列選定一個樞紐元素,執行完函數之后返回分割元素所在的位置,
            // ?在分割元素之前的元素都小于樞紐元素,在它后面的元素都大于這個元素
            int ?Partition( int ?array[],? int ?low,? int ?high)
            {
            ????
            // ?采用子序列的第一個元素為樞紐元素
            ????
            // ?非常奇怪,如果我把選擇樞紐元素的算法改成注釋掉的那一行那么就會出錯(不是必現的)
            ????
            // ?難道樞紐元素的選擇也會對這個算法產生影響?
            ????
            // ?我在快速排序算法中測試了這個函數,兩種選擇樞紐元素的算法最后得到的結果都是正確的~~
            ????
            // int?pivot?=?array[(low?+?high)?/?2];
            ???? int ?pivot? = ?array[low];

            ????
            while ?(low? < ?high)
            ????
            {
            ????????
            // ?從后往前在后半部分中尋找第一個小于樞紐元素的元素
            ???????? while ?(low? < ?high? && ?array[high]? >= ?pivot)
            ????????
            {
            ????????????
            -- high;
            ????????}


            ????????
            // ?將這個比樞紐元素小的元素交換到前半部分
            ????????Swap( & array[low],? & array[high]);

            ????????
            // ?從前往后在前半部分中尋找第一個大于樞紐元素的元素
            ???????? while ?(low? < ?high? && ?array[low]? <= ?pivot)
            ????????
            {
            ????????????
            ++ low;
            ????????}


            ????????
            // ?將這個比樞紐元素大的元素交換到后半部分
            ????????Swap( & array[low],? & array[high]);
            ????}


            ????
            // ?返回樞紐元素所在的位置
            ???? return ?low;
            }


            // ?尋找數組array中區間為[low,?high]中的第n大的元素,
            // ?如果n大于這個區間的元素個數就返回-1
            // ?非遞歸實現,這個非遞歸的實現很是簡單,就是把幾個出口的遞歸調用改寫成循環就好了~~
            int ?nthElement2( int ?array[],? int ?low,? int ?high,? int ?n)
            {
            ????
            if ?(low? > ?high? || ?n? < ? 1 ? || ?n? > ?high? - ?low? + ? 1 )
            ????
            {
            ????????
            return ? - 1 ;
            ????}


            ????
            int ?i;
            ????
            while ?( 1 )
            ????
            {
            ????????i?
            = ?Partition(array,?low,?high);

            ????????
            if ?(low? + ?n? - ? 1 ? == ?i)
            ????????
            {
            ????????????
            return ?array[i];
            ????????}

            ????????
            else ? if ?(low? + ?n? - ? 1 ? < ?i)
            ????????
            {
            ????????????
            // return?nthElement(array,?low,?i?-?1,?n);
            ????????????high? = ?i? - ? 1 ;
            ????????}

            ????????
            else ? if ?(low? + ?n? - ? 1 ? > ?i)
            ????????
            {
            ????????????
            // return?nthElement(array,?i?+?1,?high,?n?-?(i?-?low?+?1));
            ????????????low? = ?i? + ? 1 ;
            ????????????n?
            = ?n? - ?(i? - ?low? + ? 2 );
            ????????}

            ????}

            }


            // ?尋找數組array中區間為[low,?high]中的第n大的元素,
            // ?如果n大于這個區間的元素個數就返回-1
            // ?遞歸實現
            int ?nthElement( int ?array[],? int ?low,? int ?high,? int ?n)
            {
            ????
            if ?(low? > ?high? || ?n? < ? 1 ? || ?n? > ?high? - ?low? + ? 1 )
            ????
            {
            ????????
            return ? - 1 ;
            ????}


            ????
            int ?i? = ?Partition(array,?low,?high);

            ????
            if ?(low? + ?n? - ? 1 ? == ?i)
            ????
            {
            ????????
            return ?array[i];
            ????}

            ????
            else ? if ?(low? + ?n? - ? 1 ? < ?i)
            ????
            {
            ????????
            return ?nthElement(array,?low,?i? - ? 1 ,?n);
            ????}

            ????
            else ? if ?(low? + ?n? - ? 1 ? > ?i)
            ????
            {
            ????????
            return ?nthElement(array,?i? + ? 1 ,?high,?n? - ?(i? - ?low? + ? 1 ));
            ????}

            }


            // ?調整堆數組
            // ?array是待調整的堆數組,i是待調整的數組元素的位置,length是數組的長度
            void ?HeapAdjust( int ?array[],? int ?i,? int ?length)
            {
            ????
            int ?child,?temp;

            ????
            for ?(temp? = ?array[i];? 2 ? * ?i? + ? 1 ? < ?length;?i? = ?child)
            ????
            {
            ????????child?
            = ? 2 ? * ?i? + ? 1 ;

            ????????
            // ?得到子結點中較小的結點
            ???????? if ?(child? != ?length? - ? 1 ? && ?array[child? + ? 1 ]? > ?array[child])
            ????????????
            ++ child;

            ????????
            // ?如果較小的子結點大于父結點那么把較小的子結點往上移動,替換它的父結點
            ???????? if ?(temp? < ?array[child])
            ????????
            {
            ????????????array[i]?
            = ?array[child];
            ????????}

            ????????
            else ???? // ?否則退出循環
            ???????? {
            ????????????
            break ;
            ????????}

            ????}


            ????
            // ?最后把需要調整的元素值放到合適的位置
            ????array[i]? = ?temp;
            }

            // ?堆排序算法
            void ?HeapSort( int ?array[],? int ?length)
            {
            ????
            // ?調整序列的前半部分元素,調整完之后第一個元素是序列的最大的元素
            ???? for ?( int ?i? = ?length? / ? 2 ? - ? 1 ;?i? >= ? 0 ;? -- i)
            ????
            {
            ????????HeapAdjust(array,?i,?length);
            ????}


            ????
            // ?從最后一個元素開始對序列進行調整,不斷的縮小調整的范圍直到第一個元素
            ???? for ?( int ?i? = ?length? - ? 1 ;?i? > ? 0 ;? -- i)
            ????
            {
            ????????
            // ?把第一個元素和當前的最后一個元素交換,
            ????????
            // ?保證當前的最后一個位置的元素都是在現在的這個序列之中最大的
            ????????Swap( & array[ 0 ],? & array[i]);

            ????????
            // ?對當前的序列進行調整,調整完之后保證第一個元素是當前序列的最大值
            ????????HeapAdjust(array,? 0 ,?i);
            ????}

            }


            int ?main( void )
            {
            ????
            int ?array[ 10 ];
            ????srand(time(NULL));

            ????
            int ?n;
            ????printf(
            " input?n:\n " );
            ????scanf(
            " %d " ,? & n);

            ????
            // ?測試遞歸程序
            ????printf( " 測試算法的遞歸函數實現\n " );
            ????CreateNewArray(array,?
            10 );
            ????DisplayArray(array,?
            10 );
            ????
            int ?i? = ?nthElement(array,? 0 ,? 9 ,?n);
            ????
            ????HeapSort(array,?
            10 );
            ????printf(
            " after?Heap?Sort:\n " );
            ????DisplayArray(array,?
            10 );

            ????printf(
            " \nfind?%d?=?%d\n " ,?n,?i);
            ????
            if ?(array[n? - ? 1 ]? == ?i)
            ????
            {
            ????????printf(
            " found!!\n " );
            ????}


            ????
            // ?測試非遞歸函數的實現
            ????printf( " 測試算法的遞歸函數實現\n " );
            ????CreateNewArray(array,?
            10 );
            ????DisplayArray(array,?
            10 );
            ????i?
            = ?nthElement2(array,? 0 ,? 9 ,?n);

            ????HeapSort(array,?
            10 );
            ????printf(
            " after?Heap?Sort:\n " );
            ????DisplayArray(array,?
            10 );

            ????printf(
            " \nfind?%d?=?%d\n " ,?n,?i);
            ????
            if ?(array[n? - ? 1 ]? == ?i)
            ????
            {
            ????????printf(
            " found!!\n " );
            ????}



            ????system(
            " pause " );

            ????
            return ? 0 ;
            }

            posted on 2006-07-08 02:04 那誰 閱讀(3315) 評論(8)  編輯 收藏 引用 所屬分類: 算法與數據結構

            評論

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            使用STL里面的partial_sort很簡單的就可以得到一個序列中第N大的元素了。
            2006-07-08 10:29 | 3×7=51

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            犯錯誤了,使用STL里面的nth_element才是最好的辦法
            2006-07-08 10:59 | 3×7=51

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            我不否認有現成的可以用,但是我更愿意去了解其中的原理~~
            2006-07-08 12:38 | 創系

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            恕我直言,我覺得你這種方法并不是個好方法。等有時間我跟你討論一下這個問題還有什么解決方案。不過你可以去看下stl的實現(我自己還沒看)。
            2006-07-08 16:55 | 3×7=51

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            贊樓主自己思考問題:)
            2007-03-30 14:40 | wtommy

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            // int pivot = array[(low + high) / 2];
            采用這句的時候會出問題,在調試中發現,當pivot本身就是數組中最大值時,low和high的會全部循環完,而跳出循環,沒有實現交換的目的;
            可能是對算法理解有問題,不應該是low和high進行交換,應該是是和pivot進行交換
            2007-06-18 20:14 | stream

            # re: [算法問題]尋找一個序列中第n大的元素  回復  更多評論   

            我覺得stream說的對,應該是和pivot交換。
            2007-12-04 05:08 | alexandercer

            # re: [算法問題]尋找一個序列中第n大的元素[未登錄]  回復  更多評論   

            用紅黑樹數組,在紅黑樹中的每個節點都加入左邊和有邊的節點的數目,如果比左節點數目大就向左走,比右邊節點數目大,就減去這個數字再向右走,這樣一直走下去就找到了
            2015-02-01 22:25 | shawn
            国产精品狼人久久久久影院 | 99久久免费国产精品特黄| 无码精品久久久久久人妻中字| 精品久久久久久国产三级| 亚洲狠狠综合久久| 88久久精品无码一区二区毛片| 久久97精品久久久久久久不卡| 久久久久久九九99精品| 久久这里的只有是精品23| 亚洲国产精品无码久久青草 | 久久久久国产成人精品亚洲午夜| 日本免费一区二区久久人人澡| 国产精品久久久久久福利漫画| 精品999久久久久久中文字幕| 久久99精品久久久久久 | 久久综合九色综合欧美就去吻| 久久久精品视频免费观看| 午夜精品久久久久| 久久久久亚洲AV无码永不| 久久99国产精品久久99| 久久精品免费大片国产大片| 中文字幕精品久久| 久久久久99精品成人片试看| 国产免费久久久久久无码| 久久午夜无码鲁丝片秋霞 | 色偷偷久久一区二区三区| 日本一区精品久久久久影院| 武侠古典久久婷婷狼人伊人| 亚洲va中文字幕无码久久| 99久久精品国产一区二区蜜芽| 国产精品一区二区久久精品涩爱| 久久w5ww成w人免费| 久久99久久成人免费播放| 亚洲精品国产美女久久久| 婷婷综合久久中文字幕| 久久人人爽人人爽人人片AV东京热| 精品久久久久久无码中文字幕一区| 久久久久人妻精品一区三寸蜜桃| 午夜人妻久久久久久久久| 久久久久亚洲AV成人网人人网站| 久久久无码一区二区三区 |