免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1001 | 回复: 0
打印 上一主题 下一主题

[算法] 经典排序算法的C++实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-04-23 12:21 |只看该作者 |倒序浏览
1、冒泡排序  O(n2)
每一次把最大的移动到最右端,第一次从0~n-1中找到最大的放到n-1处,第二次从0~n-2中找到最大的放到n-2处……

classBubbleSort {
public:
    int* bubbleSort(int* A, intn) {
        inti,j,temp = 0;
        for(i = 1;i < n;i++)
            for(j = 0; j < n - i;j++) {
            if(A[j] > A[j + 1]) {
                temp = A[j + 1];
                A[j + 1] = A[j];
                A[j] = temp;
            }
        }
        returnA;
    }
};
2、选择排序  O(n2)
先把0处的看作最小值,从1~n-1中找到比它小的值,交换;再把1处的看作最小值,从2~n-1中找到比他小的,交换;……
classSelectionSort {
public:
    int* selectionSort(int* A, intn) {
        if(n == 0) returnA;
        inti,j,min = 0,temp;
        for(i = 0;i < n;i++) {
            min = i;
            for(j = i+1;j < n;j++) {
                if(A[j] < A[min]) {
                    min = j;
                }
            }
           temp = A[i];
           A[i] = A[min];
           A[min] = temp;                    
        }      
        returnA;
    }
};

3、插入排序  O(n2)
先把0处看作已排序的序列,将1~n-1处逐个地与0处比较,若比0处小,则将其插入到已排序的序列中;……;假设0~3已排序,将4~n-1处依次与3处比较,若小于3处,则将其插入到0~3的适当位置;……
classInsertionSort {
public:
    int* insertionSort(int* A, intn) {
        inti,j,k,temp;
        for(i = 1;i < n;i++) {
            k = i;
            for(j = i-1;j >=0;j--) {
            if(A[k] < A[j]) {
                temp = A[k];
                A[k] = A[j];
                A[j] = temp;
                k = j;
            }               
            }                     
        }
         returnA;  
    }
};

4、归并排序(递归)  O(NlogN)
先将序列分成2个子序列,再分成4个,……,直到所有子序列都只含一个元素;对每个子序列排序,再将相邻的两个已排序子序列归并为一个排序序列,依次类推,最后归并出原序列的排序序列。
classMergeSort {
public:

    voidMerge(int* A,intstart,intmiddle,intend) {
        inttemp[end-start +1];
        intk = 0;
        for(inti = start,j = middle + 1;i <= middle || j <= end;k++) {
            if(i <= middle && j <= end) {
                if(A[i] < A[j]) {
                temp[k] = A[i];
                i++;
            }
            else{
                temp[k] = A[j];
                j++;
            }
            }
            elseif(i <= middle) {
                temp[k] = A[i];
                i++;
            }
            else{
                temp[k] = A[j];
                j++;
            }
                     
        }
        for(intm = 0;m < k;m++)
            A[start + m] = temp[m];
    }
    voidDivide(int* A,intstart,intend) {

        if(start < end) {
            intm = (start + end)/2;
            Divide(A,start,m);
            Divide(A,m+1,end);
            Merge(A,start,m,end);
        }
      
    }
    int* mergeSort(int* A, intn) {
        Divide(A,0,n-1);
        returnA;
    }
};

5、快速排序(递归)  O(NlogN)
先从序列中选取一个元素为基数,一般选最左边一个;两个指针i、j分别从序列的头尾向中间遍历;j从右到左找到小于基数的元素(j处),复制到基数处(i处),i++;然后i从左向右找到大于基数的元素(i处),复制到j处,j--;依次类推,直到i与j相遇使i>=j,while循环结束,此时已把序列分成左右两个子序列,左边小于基数,右边大于基数;再将左右子序列当做未排序序列进行递归。
class QuickSort {
public:
    void Quick(int* A,int start,int end) {
        if (start >= end) return;
        else {
            int i = start,j = end;
            int base = A[i];
            while (i < j) {
                while (i < j && A[j] > base) j--;
                if (i < j) {
                    A[i] = A[j];
                    i++;
                }
                while (i < j && A[i] < base) i++;
                if (i < j) {
                    A[j] = A[i];
                    j--;
                }
            }
            A[i] = base;
            Quick(A,start,i - 1);
            Quick(A,i + 1,end);
        }
    }
    int* quickSort(int* A, int n) {
        // write code here
        Quick(A,0,n-1);
        return A;
    }
};

6、堆排序 O(NlogN)
堆实际上是一种思想,不是一种数据存储结构,堆中数据的逻辑结构与完全二叉树一样,设总共有n个结点,则叶结点个数为n+1/2或者n/2,则非叶子结点个数为n-1/2或者n/2,当n能被2整除时为n/2,不能被整除时为n-1/2。
思路:
(1)堆化数组。给定一个长度为n的乱序数组,若要递增排序,则先将其堆化(按层序存储),即把原数组调整为大端堆。
(2)取堆顶元素放入数组末尾。每次将堆顶元素与数组末尾元素交换。
(3)调整交换元素后的堆。再从堆顶到第n-2个元素调整数组为大端堆,直到n-2=1为止,即堆中只剩下一个元素未放入排序序列为止。
classHeapSort {
public:
     
    void heapify(int* A,inti,intn) {
        intj,temp;
        temp = A[i];
        j = 2*i + 1;
         
        while(j < n) {
            if(j + 1< n && A[j+1] > A[j]) j++;
            if(A[j] <= temp) break;
                A[i] = A[j];
                i = j;
                j = 2*i +1;

        }
        A[i] = temp;
        return;
    }
     
    int* heapSort(int* A, intn) {
        // write code here
        int temp;
        for(int m = n/2- 1;m >= 0;m--)
            heapify(A,m,n);
        for(int k = n-1;k >= 1;k--) {
            temp = A[k];
            A[k] = A[0];
            A[0] = temp;
            heapify(A,0,k);
        }
        return A;
    }
};


7、希尔排序 O(NlogN)
插入排序的改进。每一次比较的步长是变化的。例如,长度为n的数组,第一次设置步长为n/2,认为前n/2个数已经排序,从第n/2+1个开始,将其逐个与第1个、2个……比较,大于则交换,小于则不做操作。然后减小步长,继续以上步骤直到步长变为1.
classShellSort {
public:
    int* shellSort(int* A, intn) {
        // write code here
        intspan = n/2;
        inti,j,temp;
         
        while(span >= 1) {
            for(i = span;i < n;i++) {
                j = i - span;
                while(j >= 0) {
                    if(A[j] > A[i]) {
                        temp = A[j];
                        A[j] = A[i];
                        A[i] = temp;                        
                    }
                    j -= span;
                }
            }
            span--;
        }
        returnA;
    }
};

8、计数排序 O(N)
(1)先确认待排序数组A元素的取值范围,相当于找出最大值max和最小值min,桶C的大小必须要能包含所有的元素。
(2)顺序遍历数组A,把A[i]与桶C的下标对应起来,即,将C[A[i]-min]加1。这样A最小的元素与C的第一个下标对应,最大元素与C的最后一个下标对应。这个过程相当于把A中元素装入对应的桶中。
(3)顺序遍历桶C,把桶中元素按顺序倒出来,就是从小到大的已排序序列。
classCountingSort {
public:
    int* countingSort(int* A, intn) {
        // write code here
        intmax = A[0],min = A[0];
        for(inti = 0;i < n;i++) {
            if(A[i] > max) max = A[i];
            if(A[i] < min) min = A[i];
        }         
        intsizeC = max - min + 1;
        int*C = newint[sizeC];
        for(inti = 0;i < sizeC;i++)
            C[i] = 0;         
        for(intj = 0;j < n;j++) {
            C[A[j]-min]++;
        }
        intz = 0;
        for(intm = 0;m < sizeC;m++) {
            while(C[m] > 0) {
                A[z] = m + min;
                z++;
                C[m]--;
            }            
        }
        delete []C;
        returnA;
    }
};

9、基数排序 O(N)
先根据个位把各元素入桶,把桶中元素倒出来得到按个位排序的序列;再按照十位把各元素入桶,倒出来得到按十位排序的序列;以此类推……
注:A中数据小于2000.
一维数组实现:
classRadixSort {
public:
    int* radixSort(int* A, intn) {
        // write code here
        intC[10];
        intdivisor[5] = {1,10,100,1000,10000};
        int*B = newint[n];
        for(inti = 0;i < 4;i++) {
            for(intj = 0;j < 10;j++)
                C[j] = 0;
            for(intk = 0;k < n;k++) {
                intunit = (A[k]%divisor[i+1])/divisor[i];
                C[unit]++;
            }
            for(intj = 1;j < 10;j++)
                C[j] += C[j-1];
            
            for(intk = n-1;k >= 0;k--) {
                intunit = (A[k]%divisor[i+1])/divisor[i];
                B[C[unit]-1] = A[k];
                C[unit]--;
            }
            for(intj = 0;j < n;j++)
            A[j] = B[j];         
        }
        delete []B;
        B = NULL;
        returnA;
    }
};

二维数组实现:
class RadixSort {
public:   
int* radixSort(int* A, int n) {
        // write code here
        vector<deque<int> > bucket(10);
        int divisor[] = {1,10,100,1000,10000};
        for (int i = 0;i < 4;i++) {
            for (int j = 0;j < n;j++) {
                int unit = (A[j]%divisor[i+1])/divisor[i];
                bucket[unit].push_back(A[j]);
            }
            for (int j = 0, k = 0;j < 10;j++) {
                while (!bucket[j].empty()) {
                    A[k++] = bucket[j].front();
                    bucket[j].pop_front();
                }
            }
        }
        return A;
    }
};
10、小范围排序
已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。
选择改进的堆排序。根据题意,最小值一定在A的前k(0~k-1)个元素内、次小值一定在A的第二组k(1~k)个元素内,以此类推,每次取原数组A的k个元素进行堆排序,然后把堆顶元素放入A的已排序序列中,(0~k-1)排序的堆顶赋值给A[0],(1~k)排序的堆顶赋值给A[1],以此类推。最后剩下A中最后的k个元素(k-n~n-1),进行标准的堆排序,第一次是K个元素的堆,排序后将堆顶赋值给A[n-k],紧接着把堆尾元素赋值给堆顶,再排序,此时只是k-1个元素的堆,依次类推,每次把堆顶元素放入A中已排序序列后,都把堆尾元素赋值到堆顶,同时堆的元素个数减1,直到堆的元素个数为1,整个排序结束。
class ScaleSort {
public:
void heapify(int* B,int i,int k) {
        int j,ex;
        ex = B[i];
        j = 2*i + 1;
        while (j < k) {
            if (j + 1 < k && B[j + 1] < B[j])
                j++;            
            if (B[j] >= ex) break;           
            B[i] = B[j];
            i = j;
            j = 2*i + 1;
        }
        B[i] = ex;
        return;
    }

    vector<int> sortElement(vector<int> A, int n, int k) {
        // write code here
        int m = 0,exc;
       int *temp = new
       int[k];
        for (int l = 0;l < k;l++) {
            temp[l] = A[l];
        }
        for (int i = k/2-1;i >= 0;i--)
        heapify(temp,i,k);

        for (int i = k;i < n;i++) {
            A[i-k] = temp[0];
            temp[0] = A[i];
            heapify(temp,0,k);
        }

        for (int j = n-k;j < n;j++) {
            A[j] = temp[0];
            k--;
            temp[0] = temp[k];
            heapify(temp,0,k);
        }

        delete []temp;
        temp = NULL;
        return A;
    }
};

11、求一个数组排序后相邻元素之差的最大值,时间复杂度为O(n)、空间复杂度为O(n)
若先排序后求差值则只有桶排序满足时间复杂度,但是桶排序不能满足空间复杂度,桶排序的空间复杂度为O(max-min)。因此要用改进的桶排序但是又没有真正的排序。

①、求出数组A的最大值max和最小值min,并把区间max-min平均分成n份,每份大小为interval,则只需要n+1个桶;
②、用A[i]-min/interval的整数部分确定A[i]该入的桶,并定义三个大小为n+1的数组,bucket记录n+1个桶每个桶的入桶元素个数,max_bucket记录每个桶中最大值,min_bucket记录每个桶中最小值;
③、遍历bucket数组,将后一个桶的最小值min_bucket[j]减去前一个桶的最大值max_bucket[j-1],记录下最大的差值,返回该差值。

class Gap {
public:
    int maxGap(vector<int> A, int n) {
        int max = A[0],min = A[0];

        for (int i = 1;i < n;i++) {
            if (A[i] > max) max = A[i];
            else
                if (A[i] < min) min = A[i];
        }

        float interval = (float)(max - min)/n;

        int bucket[n+1];
        for (int j = 0;j < n+1;j++)
            bucket[j] = 0;

        
int max_bucket[n+1],min_bucket[n+1];

        for (int i = 0;i < n;i++) {
            int j = (int)(A[i]-min)/interval;
            bucket[j]++;
            min_bucket[j] = A[i];
            max_bucket[j] = A[i];
        }

        for (int i = 0;i < n;i++) {
            int j = (int)(A[i]-min)/interval;
            if (A[i] > max_bucket[j]) max_bucket[j] = A[i];
            if (A[i] < min_bucket[j]) min_bucket[j] = A[i];
        }

        int maxGap = 0;
        for (int i = 0,j = 1;j < n+1;j++) {
            if (bucket[j] > 0) {
                if (min_bucket[j]-max_bucket[i] > maxGap)
                    maxGap = min_bucket[j] - max_bucket[i];
                i = j;
            }               
        }
        return maxGap;
    }
};
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP