常用的十种排序

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存放在归并时完成归并的数组,然后再将其赋值给原数组。

class Solution {
private:
    void merge(vector<int> &nums, int left, int mid, int right)
    {
        int i = left, j = mid + 1, index = 0;
        int count = 0;
        vector<int> tmp(right - left + 1);
        while (i <= mid && j <= right) {
            if (nums[i] <= nums[j]) {
                tmp[index++] = nums[i++];
            }
            else {
                tmp[index++] = nums[j++];
            }
        }
        while (i <= mid) {
            tmp[index++] = nums[i++];
        }
        while (j <= right) {
            tmp[index++] = nums[j++];
        }
        for (i = 0; i < tmp.size(); ++i) {
            nums[left + i] = tmp[i];
        }
        return ;
    }
    void mergeSort(vector<int> &nums, int left, int right)
    {
        if (left >= right) {
            return ;
        }

        int mid = left + (right - left) / 2;
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        merge(nums, left, mid, right);
    }
public:
    int reversePairs(vector<int>& nums) {
        return mergeSort(nums, 0, nums.size() - 1);
    }
};

单链表归并

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;
}

 

posted on 2018-09-16 15:25  tianzeng  阅读(519)  评论(0编辑  收藏  举报

导航