zoukankan      html  css  js  c++  java
  • 常用的十种排序

    1、直接插入排序

      最好O(n),最坏时间O(n^2),较稳定

      基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

    #include <iostream>
    using namespace std;
    
    int main()
    {
        int a[]={5,2,6,3,9};
        int len=sizeof(a)/sizeof(a[0]);
        
        for(int i=1;i<len;++i)
        {
            if(a[i]<a[i-1])
            {
                int t=a[i],j;
                for(j=i-1;j>=0&&a[j]>t;--j)
                    a[j+1]=a[j];
                    
                a[j+1]=t;
            }
        }
        
        for(int i=0;i<len;++i)
            cout<<a[i]<<" ";
        cout<<endl;
        
        return 0;
    }

    2、希尔排序

      时间复杂度:O(n*log(n)),不稳定

      由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

      直接插入排序的的步长是为1的,而希尔排序向前比较是以一定步长向前比较。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        vector<int> arr{5,2,6,3,9};
        for(int gap=arr.size()/2;gap>0;gap/=2)//步长
        {
            for(int i=gap;i<arr.size();++i)//和直接插入排序一样,只不过是每次向前移动k步比较而不是移动一步比较
            {
                int tmp=arr[i];
                int j=i-gap;
                while(j>=0&&arr[j]>tmp)
                {
                    arr[j+1]=arr[j];
                    j-=gap;
                }
                arr[j+gap]=tmp;
            }
        }
        for_each(arr.begin(),arr.end(),[](int i)->void{cout<<i<<" ";});
        cout<<endl;
        return 0;
    }

    3、简单选择排序

      最好:O(n^2),最坏:O(n^2),不稳定  

      基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        vector<int> arr{5,2,6,3,9};
        for(int i=0;i<arr.size()-1;++i)
        {
            int minIndex=i;
            for(int j=i+1;j<arr.size();++j)
            {
                if(arr[j]<arr[minIndex])
                    minIndex=j;
            }
            if(minIndex!=i)
                swap(arr[minIndex],arr[i]);
        }
        for_each(arr.begin(),arr.end(),[](int i)->void{cout<<i<<" ";});
        cout<<endl;
        return 0;
    }

    4、堆排序

      最好:nlog(n),最坏:nlog(n),不稳定

      堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

    初建堆:

      将一个任意序列看成是对应的完全二叉树,由于叶结点可以视为单元素的堆,因而可以反复利用上述调整的算法,自底向上逐层把所有子树调整为堆,直到整个完全二叉树为堆。最后一个非叶节点位于n/2(向下取整)个位置,n为二叉树结点数目,因此,筛选从n/2(向下取整)个结点开始,逐层向上倒退,知道根节点。

    调整堆:

             这是为了保持堆的特性而做的一个操作。对某一个节点为根的子树做堆调整,其实就是将该根节点进行“下沉”操作(具体是通过和子节点交换完成的),一直下沉到合适的位置,使得刚才的子树满足堆的性质。

    1. 在对应的数组元素A[i], 左孩子A[LEFT(i)], 和右孩子A[RIGHT(i)]中找到最大的那一个,将其下标存储在largest中。
    2. 如果A[i]已经就是最大的元素,则程序直接结束。
    3. 否则,i的某个子结点为最大的元素,将A[largest]与A[i]交换。
    4. 再从交换的子节点开始,重复1,2,3步,直至叶子节点,算完成一次堆调整。

           这里需要提一下的是,一般做一次堆调整的时间复杂度为log(n)。

    堆排序:

      数组储存成堆的形式之后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n-2]交换,再对A[0…n-3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    /*
    对于具有n个节点的完全二叉树,如果按照从上(根节点)到下(叶节点)和从左到右的顺序对二叉树中的所有节点从0开始到n-1进行编号,则对于任意的下标为k的节点,有:
    如果k=0,则它是根节点,它没有父节点;如果k>0,则它的父节点的下标为[(i-1)/2];
    如果2k+1 <= n-1,则下标为k的节点的左子结点的下标为2k+1;否则,下标为k的节点没有左子结点.
    如果2k+2 <= n-1,则下标为k的节点的右子节点的下标为2k+2;否则,下标为k的节点没有右子节点
    */
    class HeapSort
    {
    private:
        void adjustHeap(vector<int>& arr,int start,int end)
        {
            //2.调整堆:已知arr[start...end]中除关键字arr[start]之外均满足堆的定义
            //本函数调整arr[start]的关键字,使arr[start,end]成为一个大根堆
            int res=arr[start];
            for(int j=start*2+1;j<=end;j=j*2+1)
            {
                if(j<end&&arr[j]<arr[j+1])//找出左右子树中最大的
                    ++j;
                if(res>arr[j])
                    break;
                arr[start]=arr[j];
                start=j;//因为j和start交换了,所以要更新start的值;向下调整
            }
            arr[start]=res;
        }
    public:
        void heapSort(vector<int>& arr)
        {
            int len=arr.size();
            //1.初建堆
            for(int i=len/2-1;i>=0;--i)//可以把数组中len/2-1后的元素看做单根堆,均满足堆的定义;所以向上调整
                adjustHeap(arr,i,len-1);
    
            //堆排序
            for(int i=len-1;i>0;--i)
            {
                swap(arr[0],arr[i]);
                adjustHeap(arr,0,i-1);
            }
            return ;
        }
    };
    int main()
    {
        vector<int> arr{54,35,48,36,27,12,44,44,8,14,26,17,28};
        HeapSort hs;
        hs.heapSort(arr);
        for(auto i:arr)
            cout<<i<<" ";
        cout<<endl;
        return 0;
    }
    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Heap_sort
    {
        public:
            void build_heap(vector<int> &v);
            void adjust_heap(vector<int> &v,vector<int>::iterator i,vector<int>::iterator dis);
            void sort_heap(vector<int> &v);
            vector<int>::iterator left_child(vector<int> &v,vector<int>::iterator i);
            vector<int>::iterator right_child(vector<int> &v,vector<int>::iterator i);
    };
    //获取左节点下标 
    vector<int>::iterator Heap_sort::left_child(vector<int> &v,vector<int>::iterator i)
    {
        advance(i,distance(v.begin(),i));
        return i;
    }
    //获取右节点下标 
    vector<int>::iterator Heap_sort::right_child(vector<int> &v,vector<int>::iterator i)
    {
        advance(i,distance(v.begin(),i)+1);
        return i;
    }
    //调整堆 
    void Heap_sort::adjust_heap(vector<int> &v,vector<int>::iterator i,vector<int>::iterator dis)
    {
        vector<int>::iterator l=left_child(v,i);
        vector<int>::iterator r=right_child(v,i);
        vector<int>::iterator largest=v.begin();
        
        if((*i)<(*l)&&(l<dis))
            largest=l;
        else
            largest=i;
        
        if((*largest)<(*r)&&(r<dis))
            largest=r;
        //建的是大顶锥    
        if(largest!=i)
        {
            swap(*largest,*i);
            adjust_heap(v,largest,dis);
        }
    }
    //初建堆 
    void Heap_sort::build_heap(vector<int> &v)
    {
        for(vector<int>::iterator i=v.begin()+v.size()/2-1;i!=--v.begin();--i)
            adjust_heap(v,i,v.end());
    }
    //堆排序 
    void Heap_sort::sort_heap(vector<int> &v)
    {
        build_heap(v);//堆排序之前应该先初建堆 
        for(auto i=--v.end();i!=--v.begin();--i)
        {
            swap(*i,*(v.begin()));//交换第一个元素(最大的)与最后一个元素 
            adjust_heap(v,v.begin(),i);//交换完之后第一个元素不是最大的,要调整堆使第一个元素最大 
        }
    }
    
    int main()
    {
        vector<int> v{70,30,40,10,80,20,90,100,75,60,45};//看做完全二叉树 
        
        Heap_sort hs;//创建堆排序的对象 
        hs.sort_heap(v);
        
        for(auto i:v)
            cout<<i<<" ";
        cout<<endl;
        return 0;
    }
    View Code

    5、冒泡排序

      o(n^2),稳定

      基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。

    #include <iostream>
    #include <vector>
    using namespace std;
    int main()
    {
        vector<int> arr{70,30,40,10,80,20,90,100,75,60,45};
        int len=arr.size();
        bool flag=true;
        for(int i=0;i<len-1&&flag;++i)
        {
            flag=false;
            for(int j=0;j<len-i;++j)
            {
                if(arr[j]>arr[j+1])
                {
                    swap(arr[j],arr[j+1]);
                    flag=true;
                }
            }
        }
    
        for(auto i:arr)
            cout<<i<<" ";
        cout<<endl;
        return 0;
    }

    双向冒泡排序算法步骤

    1. 比较相邻两个元素的大小。如果前一个元素比后一个元素大,则两元素位置交换
    2. 对数组中所有元素的组合进行第1步的比较
    3. 奇数趟时从左向右进行比较和交换
    4. 偶数趟时从右向左进行比较和交换、
    5. 当从左端开始遍历的指针与从右端开始遍历的指针相遇时,排序结束
    //双向冒泡排序
    #include <iostream> 
    #include <algorithm>
    using namespace std;
    
    void per_sort(int a[],int len,int per_index)
    {
        for(int i=per_index+1;i<len;++i)
            if(a[i]<a[per_index])
                swap(a[i],a[per_index]);
    }
    
    void back_sort(int a[],int len,int back_index)
    {
        for(int i=back_index-1;i>=0;--i)
            if(a[i]>a[back_index])
                swap(a[i],a[back_index]);
    }
    
    void two_way_bubble_sort(int a[],int len)
    {
        int per_index=0,back_index=len-1;
        
        while(per_index<back_index)
        {
            per_sort(a,len,per_index);
            ++per_index;
            
            if(per_index>back_index)
                break;
            
            back_sort(a,len,back_index);
            --back_index;
        }
    }
    
    int main()
    {
        int a[]={70,30,40,10,80,20,90,100,75,60,45};
        int length=sizeof(a)/sizeof(int);
        
        two_way_bubble_sort(a,length);
        for(int i=0;i<length;++i)
            cout<<a[i]<<" ";
        cout<<endl;
        return 0;
    } 

    6、快速排序

      最好:O(nlog(n)),最坏:O(n^2),不稳定

      基本思想:选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,一部分比基准元素小,一部分大于等于基准元素,此时基准元素在其排好序后的正确位置,然后再用同样的方法递归地排序划分的两部分。

    假设待划分的序列为a[left],a[left+1]......a[right],首先将基准记录a[left]移致变量x中,使a[left]相当于空单元,然后反复进行如下两个扫描过程,知道left和right相遇。

      1.left从右向左扫描,直到a[right]<x,将a[right]移至空单元a[left]中,此时a[right]相当于空单元

      2.left从左向右扫描,直到a[left]>x,将a[left]移到空单元a[right],此时a[left]相当于空单元。

      当left和right相遇时,a[left]或a[right]相当于空单元,且a[left]左边均比它小,右边均比它大,最后将基准记录移至a[left]中,完成了一次划分,再对a[left]的左子表和右子表进行同样的划分。

    #include <iostream>
    #include <vector>
    using namespace std;
    
    class QuickSort
    {
    private:
        int pass(vector<int>& arr,int left,int right)
        {
            int temp=arr[left];
            while(left<right)
            {
                while(right>left&&temp<=arr[right])
                    --right;
                if(left<right)
                    arr[left++]=arr[right];
    
                while(right>left&&temp>arr[left])
                    ++left;
                if(left<right)
                    arr[right--]=arr[left];
            }
            arr[left]=temp;
            return left;
        }
    public:
        void quickSort(vector<int>& arr,int start,int end)
        {
            if(start<end)
            {
                int mid=pass(arr,start,end);
                quickSort(arr,start,mid-1);
                quickSort(arr,mid+1,end);
            }
            return ;
        }
    };
    int main()
    {
        vector<int> arr{70,30,40,10,80};
        QuickSort qs;
        qs.quickSort(arr,0,5);
        for(auto i:arr)
            cout<<i<<" ";
        cout<<endl;
        return 0;
    }

    三路快排

    在排序过程中分为比基准元素小的部分:[left,lt],等于基准元素的部分:[lt+1,i),大于基准元素的部分:[gt,r]

    void quick_sort3(vector<int>& arr,int left,int right)
    {
        if(left>=right)
            return ;
    
        int v=arr[left];
        int lt=left;
        int i=lt+1;
        int gt=right+1;//刚开始大于基准元素部分为空,所以gt=right+1
        while(i<gt)
        {
            if(arr[i]<v)
            {
                swap(arr[i],arr[lt+1]);
                ++lt;
                ++i;
            }
            else if(arr[i]>v)
            {
                swap(arr[i],arr[gt-1]);
                --gt;
                //++i;//换过来的此元素可能比v小所以要再次比较,不能++i
            }
            else
            {
                ++i;
            }
        }
        swap(arr[left],arr[lt]);//相当于等于基准元素部分向左扩一位
        quick_sort3(arr,left,lt-1);
        quick_sort3(arr,gt,right);
    }

    单链表快排

      slow指针及左边的元素都小于基准元素,fast指针用来遍历,当遇到比基准元素小的时候先slow后移,此时slow指向的肯定比基准元素大,在交换slow和fast指向的元素的值,相当于slow向右扩充。

    ListNode* partition(ListNode* start, ListNode* end)
    {
        ListNode* slow=start;
        ListNode* fast=slow->next;
        int key=start->val;
        while(fast!=end)
        {
            if(fast->val<key)
            {
                slow=slow->next;
                swap(slow->val,fast->val);
            }
            fast=fast->next;
        }
        swap(slow->val,start->val);
        return slow;
    }
    void quick_sort(ListNode* start,ListNode* end)
    {
        if(start==end)
            return ;
        ListNode* mid=partition(start,end);
        quick_sort(start,mid);
        quick_sort(mid->next,end);
    }

    7、归并排序

      最好:O(nlog(n)),最坏:O(nlog(n)),稳定

    算法思想:

      假设初始序列含有n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到N/2(向上取整)个长度为的有序子序列,在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的子序列,重复,知道得到长度为n的有序序列为止。

      tmp存放在归并时完成归并的数组,然后再将其赋值给原数组。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class MergeSort
    {
    private:
        void merge(vector<int>& arr,int left,int mid,int right,vector<int> tmp)
        {
            int i=left;
            int j=mid+1;
            int index=0;
            while(i<=mid&&j<=right)
            {
                if(arr[i]<arr[j])
                    tmp[index++]=arr[i++];
                else
                    tmp[index++]=arr[j++];
            }
            while(i<=mid)
                tmp[index++]=arr[i++];
            while(j<=right)
                tmp[index++]=arr[j++];
            index=0;
            while(left<=right)
                arr[left++]=tmp[index++];
    
            return ;
        }
        void mergeSrotCore(vector<int>& arr,int left,int right,vector<int> tmp)
        {
            if(left<right)
            {
                int mid=(left+right)/2;
                mergeSrotCore(arr,left,mid,tmp);
                mergeSrotCore(arr,mid+1,right,tmp);
    
                merge(arr,left,mid,right,tmp);
            }
        }
    public:
        void mergeSrot(vector<int>& arr)
        {
            vector<int> tmp(arr.size());
            mergeSrotCore(arr,0,arr.size()-1,tmp);
        }
    };
    
    int main()
    {
        vector<int> arr{70,30,40,10,80};
        MergeSort ms;
        ms.mergeSrot(arr);
        for_each(arr.begin(),arr.end(),[](int i)->void{cout<<i<<" ";});
        cout<<endl;
        return 0;
    }

    单链表归并

    ListNode* merge(ListNode* l1,ListNode* l2)
    {
        ListNode* H=new ListNode(1);
        ListNode* l=H;
        while(l1&&l2)
        {
            if(l1->val<=l2->val)
            {
                l->next=l1;
                l1=l1->next;
            }
            else
            {
                l->next=l2;
                l2=l2->next;
            }
            l=l->next;
        }
        if(l1)
            l->next=l1;
        if(l2)
            l->next=l2;
    
        return H->next;
    }
    ListNode* mergeList(ListNode* head)
    {
        if(head==nullptr||head->next==nullptr)
            return head;
    
        ListNode* pre=nullptr;
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast)
        {
            pre=slow;
            slow=slow->next;
            fast=fast->next;
            if(fast)
                fast=fast->next;
        }
        if(pre)
            pre->next=nullptr;
        ListNode* l1=mergeList(head);
        ListNode* l2=mergeList(slow);
        return merge(l1,l2);
    }

    8、基数排序

      平均时间复杂度:O(n),最好:O(n),最坏:O(n),稳定

    基本思想:

      将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

     整个算法过程描述如下: 

                    1、将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。

                    2、从最低位开始,依次进行一次排序。

                    3、这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

      基数排序的时间复杂度是 O(k•n),其中n是排序元素个数,k是数字位数。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Radix_sort
    {
        public:
            void radix_sort(vector<int> &v);
        private:
            void count_sort(vector<int> &v,int exp);
    };
    void Radix_sort::count_sort(vector<int> &v,int exp)
    {
        vector<int> tmp(10,0),ot(v.size(),0);
        for(int i=0;i<v.size();++i)
            ++(tmp.at((v.at(i)/exp)%10));
            
        for(int i=1;i<10;++i)
            tmp.at(i)+=tmp.at(i-1);
        
        for(int i=v.size()-1;i>-1;--i)
            ot.at(--(tmp.at(v.at(i)/exp%10)))=v.at(i);
            
        copy(ot.begin(),ot.end(),v.begin());
    }
    void Radix_sort::radix_sort(vector<int> &v)
    {
        int Max=*max_element(v.begin(),v.end());
        for(int exp=1;Max/exp>0;exp*=10)
            count_sort(v,exp);
    }
    int main()
    {
        vector<int> v{70,30,40,10,80,20,90,100,75,60,45};
        
        Radix_sort rs;
        rs.radix_sort(v);
        for(auto i:v)
            cout<<i<<" ";
        cout<<endl;
        
        return 0;
    }
    #include<iostream>
    using namespace std;
    #define N 10
    class RadixSort 
    {
    public:
        int* radixSort(int* A, int n,int radix)
        //基数排序:radix为关键字最高位数
        {
            int temp[10][N]={0},order[10]={0};
            int m=(int)pow((double)10,radix-1),base=1;
            while(base<=m)
            {
                int i,k;
                for(i=0;i<n;i++)
                {
                    int lsd=(A[i]/base)%10;
                    temp[lsd][order[lsd]]=A[i];
                    order[lsd]++;
                }
                for(i=0,k=0;i<10;i++)
                {
                    if(order[i])
                    {
                        int j;
                        for(j=0;j<order[i];j++,k++)
                            A[k]=temp[i][j];
                    }
                    order[i]=0;
                }
                base*=10;
            }
            return A;
        }
    };
    int main()
    {
        int arr[]={5412,351,4821,362,127,12,441,414,8,1499,2226,5717,268};
        RadixSort a;
        a.radixSort(arr,13,4);
        for(int i=0;i<13;i++)
            cout<<arr[i]<<" ";
        cout<<endl;
        return 0;
    }
    View Code

    9、桶排序

      平均时间复杂度:O(n),最好:O(n),最坏:O(n),不稳定

     算法描述和分析

    1. 设置一个定量的数组当作空桶子。
    2. 寻访串行,并且把项目一个一个放到对应的桶子去。
    3. 对每个不是空的桶子进行排序。
    4. 从不是空的桶子里把项目再放回原来的串行中。
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include <ctime>
    using namespace std;
    
    class Rand
    {
        public:
            int operator() ()
            {
                //srand((unsigned)time(NULL));    
                return rand()%(100-1)+1;
            }
    };
    class Bucket_sort
    {
        public:
            void bucket_sort(vector<int> &v);
    };
    
    void Bucket_sort::bucket_sort(vector<int> &v)
    {
        //1.设置10个桶 
        vector<vector<int> > tmp(10,vector<int>(distance(v.begin(),v.end())));
        //vector<int> count(10,0);////2.获得数据的平均值 
        double avg=(*max_element(v.begin(),v.end())-*min_element(v.begin(),v.end())+1)/10.0;
        //cout<<avg<<endl;
        
        for(auto it=v.begin();it!=v.end();++it)
        {
            //3.确定桶号
            int num=(*it-*min_element(v.begin(),v.end()))/avg; 
            //cout<<num<<endl;
            
            //4.把数据装入桶中 
            if(tmp[num][0])
            {
                //此桶中有数据,用直接插入排序 
                int len=1;
                for(int i=1;i<10;++i)
                    if(tmp[num][i])
                        ++len;
                    else
                        break;
                //int t=*it;
                int j;
                for(j=len-1;j>=0;--j)
                {
                    if(*it<tmp[num][j])
                        tmp[num][j+1]=tmp[num][j];
                    else
                        break;
                }
                tmp[num][j+1]=*it;
            }
            else//桶中无数据可以直接插入 
                tmp[num][0]=*it;
        }
        //把桶中的数据按顺序放到原来的数组 
        v.clear();
        for(int i=0;i<10;++i)
        {
            if(tmp[i][0])//如果桶中有数据 
                for(int j=0;j<10&&tmp[i][j];++j)
                    v.push_back(tmp[i][j]);
        }
    }
    
    int main()
    {
        vector<int> arr(10);
        generate(arr.begin(),arr.end(),Rand());
        cout<<" 产生的随机数:"<<endl;
        for(auto i:arr)
            cout<<i<<" ";
        cout<<endl;
        
        cout<<" 排序后的数字:"<<endl;
        Bucket_sort bs;
        bs.bucket_sort(arr);
        for(auto i:arr)
            cout<<i<<" ";
        cout<<endl;
        return 0;
    }

    10、计数排序

     算法简介

      计数排序(Counting sort)是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i+Min的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。

    1. 找出待排序的数组中最大和最小的元素
    2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
    3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
    4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

      计数排序是一种以空间换时间的排序算法,并且只适用于待排序列中所有的数较为集中时,比如一组序列中的数据为0 1 2 3 4 999;就得开辟1000个辅助空间。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    class Count_sort
    {
        public:
            void count_sort(vector<int> &v);
    };
    void Count_sort::count_sort(vector<int> &v)
    {
        int Min=*min_element(v.begin(),v.end());
        int Max=*max_element(v.begin(),v.end());
        vector<int> count(Max-Min+1);//数据范围
        
        for(int i=0;i<v.size();++i)//把数据存入计数数组,计算每个下表的数字个数 
            ++(count.at(v.at(i)-Min));
        
        for(int i=0,index=0;i<Max-Min+1;++i)
            while((count.at(i))--)
                v.at(index++)=i+Min;
    }
    int main()
    {
        vector<int> v{5,6,3,8,4,5,2,6,7,6,3,9};
        Count_sort cs;
        cs.count_sort(v);
        for(auto i:v)
            cout<<i<<" ";
        cout<<endl;
        
        return 0;
    }
    #include<iostream>
    #include<cstdlib>
    using namespace std;
    class CountingSort
    {
    public:
        int* countingSort(int* A, int n)
        //¼ÆÊýÅÅÐò
        {
            int i,j,min,max;
            for(i=1,min=max=A[0];i<n;i++)
            {
                if(A[i]<=min)
                    min=A[i];
                if(A[i]>max)
                    max=A[i];
            }
            int *counts=(int *)calloc(max-min+1,sizeof(int));
            if(!counts)
                exit(-1);
            for(i=0;i<n;i++)
                counts[A[i]-min]++;
            for(i=0,j=0;i<max-min+1;i++)
                while(counts[i])
                {
                    A[j]=i+min;
                    counts[i]--;
                    j++;
                }
            free(counts);
            counts=NULL;
            return A;
    
        }
    };
    int main()
    {
        int arr[]={54,35,48,36,27,12,44,44,8,14,26,17,28};
        CountingSort a;
        a.countingSort(arr,13);
        for(int i=0;i<13;i++)
            cout<<arr[i]<<" ";
        cout<<endl;
        return 0;
    }
    View Code

    分块查找

     

    1.将待查找关键字k与索引表中的关键字进行比较,已确定待查找记录所在的块,可用折半查找或顺序查找

    2.进一步用顺序查找,在相应的块内查找关键字为k的元素。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    struct block
    {
        int start,key;
    }block[3];
    typedef struct block B;
    
    bool cmp(const B &x,const B &y)
    {
        if(x.key<=y.key)
            return true;
        else
            return false;
    }
    
    int block_search(vector<int> v,int num)
    {
        //分为三块,计算每个块内有多少元素 
        int step=ceil(v.size()/3.0);//其实也就是块的长度,最后一个元素的下标 
        
        for(int i=0,j=0;i<3;++i)//3块 
        {
            block[i].start=j;
            if(j+step<v.size())//最后一个块内的元素不一定等于setp,防止越界 
                j+=step;
            else
                j=v.size();
            block[i].key=*max_element(v.begin()+block[i].start,v.begin()+j);//key为每个块内的最大的元素 
        }
        sort(block,block+3,cmp);
        
        //找到第一个key小于num的block
        int i=0;
        for(;block[i].key<num&&i<3;++i);
        
        int j=block[i].start;
        for(;j<(block[i].start+step)&&((v.at(j))!=num);++j);
        
        if(j>=block[i].start+step)
        {
            cerr<<" 要查找的数不存在"<<endl;
            return -1;
        }
        return v.at(j);
    }
    int main()
    {
        vector<int> v{70,30,40,10,80,20,90,100,75,60,45};
        
        cout<<block_search(v,80)<<endl;
        return 0;
    }

    计算式查找法

    #include <iostream>
    #include <vector>
    #include <vector>
    using namespace std;
    
    typedef struct Hash
    {
        int key;
        struct Hash *next;
        Hash()
        {
            key=0;
            next=nullptr;
        }
    }Hash;
    
    Hash *insert_hash(Hash *head,const int &key)
    {
        Hash *t=new Hash();
        t->key=key;
        Hash *p0=head,*p1=nullptr;
        if(!head)
        {
            head=t;
            t->next=nullptr;
        }
        else
        {
            while((p0->key<t->key)&&(p0->next!=nullptr))
            {
                p1=p0;
                p0=p0->next;
            }
            
            if(t->key<=p0->key)//插到当前节点的前面 
            {
                if(p0==head)//且当前节点是第一个节点
                {
                    head=t;
                    head->next=p0;    
                }
                else
                {
                    p1->next=t;
                    t->next=p0;
                }
            }
            else//插入到当前节点的后面 
            {
                p0->next=t;
                t->next=nullptr;
            }
        }
        return head;
    }
    pair<int,int> hash_search(Hash *h,int key)
    {
        int j=0;
        Hash *t=h;
        while(t)
        {
            if(t->key==key)
                break;
            ++j;
            t=t->next;
        }    
        if(!t)
            return make_pair(-1,-1);
        else
            return make_pair(-1,j);
    }
    int main()
    {
        vector<Hash*> h(100);
        vector<int> v{70,30,40,10,48,24,90,100,75,60,45};
        for(int i=0;i<h.size();++i)
            h.at(i)=nullptr;
        
        for(int i=0;i<v.size();++i)
        {
            int t=v.at(i)%(v.size()+1);
            h.at(t)=insert_hash(h.at(t),v.at(i));
        }
        
        for(int i=0;i<v.size();++i)
        {
            Hash *t=h.at(i);
            while(t)
            {
                cout<<t->key<<" ";
                t=t->next;
            }
            cout<<endl;
        }
        
        pair<int,int> p;
        for(int i=0;i<v.size();++i)
        {
            p=hash_search(h.at(i),75);
            if(p.second!=-1)
            {
                p.first=i;
                break;
            }
        }
        cout<<"row:"<<p.first<<" col:"<<p.second<<endl;
        return 0;
    }
  • 相关阅读:
    3月4号—3月20号的计划
    Codeforces Round #344 (Div. 2) D. Messenger kmp水题
    Codeforces Round #344 (Div. 2) C. Report 水题
    整数三分(模板)
    Codeforces Round #344 (Div. 2) E. Product Sum 三分
    hdu3276 Graph and Queries 离线+treap
    bzoj1588: [HNOI2002]营业额统计 treap
    hdu5002 tree LCT
    bzoj2594 [Wc2006]水管局长数据加强版 离线+LCT维护边权
    bzoj2002 弹飞绵羊 LCT
  • 原文地址:https://www.cnblogs.com/tianzeng/p/9656265.html
Copyright © 2011-2022 走看看