牛客网算法学习记录-排序


对于一个int数组,请编写一个冒泡排序算法,对数组元素排序。

给定一个int数组A及数组的大小n,请返回排序后的数组。 

测试样例:
[1,2,3,5,2,3],6
[1,2,2,3,3,5]
测试用例子只有正数。
升序

冒泡排序:比较简单,主要就是注意排序时数组的边界。

 for(int i=0;i<n-1;i++)
       {
        for(int j=0;j<n-i-1;j++)
        {
            int temp;
           if(A[j]>A[j+1])
           {
               temp=A[j];
               A[j]=A[j+1];
               A[j+1]=temp;
           }
        }
       }     
        return A;
选择排序:比较简单,注意概念即可。
它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
 int* selectionSort(int* A, int n) {
        // write code here
        
        for(int i = 0 ; i < n ; i ++){
            int max = A[i];
            int index = i ;
            for(int j = i+1 ; j< n ;j++){
                
                if(A[j]<max){
                    max = A[j];
                    index = j;
                }
            }
            if(i != index){
                int t = A[i];
                A[i] = A[index];
                A[index] = t;
            }   
        }
        return A;
    }
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序, 时间复杂度 为O(n^2)。

主要还是注意数组边界

for(int i = 0,j=0 ;i<n;i++){
            int value = A[i];
            bool changed = false;
            for(j = i-1 ;j>=0;j--){
                if(A[j]>value){
                    A[j+1]=A[j];
                    changed =true;
                }
                else{
                    break;
                }
            }
            if(changed)
            A[j+1] = value;
            
        }
        return A;

归并排序:先通过递归进行切分,然后使用两个数组合并为一个数组的方法进行排序,由于递归分割的原因,每次调用排序函数时,两个分块是各自有序的



class MergeSort {
public:
    void mergeSortDepart(int *A,int first , int last){
    if(first + 1 >last)
        return;
    
    int mid = (first + last)/2;
    mergeSortDepart(A,first,mid);
    mergeSortDepart(A,mid+1,last);
    mergeSortArray(A,first,mid,last);
    
}




void mergeSortArray(int *A,int first,int mid,int last){
    int temp[last - first + 1];
    int i,j,index;
    for( i = first,j = last,index = 0; i <=mid && j<=last;){
        
        if(A[i] < A[j]){
            temp[index++] = A[i];
            i++;
        }
        else{
            temp[index++] = A[j];
            j++;
        }
        
    }
    if(i > mid){
        for(;j<=last;j++){
            temp[index++] = A[j];
        }
    }
    else if (j>last){
        for(;i<=mid;i++){
            temp[index++] = A[i];
        }
    }
    i=first;
    for(int k = 0 ; k <index;k++,i++){
        
        A[i] = temp[k];
        
    }
    
}
    
    int* mergeSort(int* A, int n) {
        // write code here
        if(A == null || n == 1){
            return A;
        }
        mergeSortDepart(A,0,n-1);
        return A;
        
    }
};


快速排序:数据结构那本书讲的挺清楚的。
一开始写错了,主要是在partition函数中的A[HIGH]>=value 没有写等于号,导致样例死循环,就是数组索引中的具体值是相等的 但是索引本身符合LOW<HIGH,所以产生了死循环


void QSort(int *A, int low, int high) {
if (low < high) {
int pivotal = Partition(A, low, high);
cout << "Qsort";
QSort(A, low, pivotal - 1);
QSort(A, pivotal + 1, high);


}


}
    
    int Partition(int *A, int low, int high) {


int  value = A[low];
while (low<high) {
cout << "while(partition)";
while (low<high&&A[high]>=value)
high--;
A[low] = A[high];
while (low < high&&A[low] <= value)
low++;
A[high] = A[low];
}
A[low] = value;
return low;
}
    
    int* quickSort(int* A, int n) {
        // write code here
        QSort(A,0,n-1);
        
        return A;
    }


堆排序:主要是借助完全二叉树的性质进行的,包括完全二叉树 和 第一个元素从1开始的数组下标的对应关系,缩短数组边界,然后按层次进行比较进行的。

void HeapSort(int *A, int length) {


for (int i = length / 2;i > 0;i--) {
HeapAdjust(A,i,length-1);
}


for (int i = length; i > 1;i--) {
int t = A[1];
A[1] = A[length];
A[length] = t;
HeapAdjust(H,1,i-1);
}


}


void HeapAdjust(int *A,int s,int m) {
//s为当前需要调整的点,m为最后一个节点的下标
int r = A[s];
for (int j = 2 * s;j <= m;j=j*2) {
if (j < m && A[j] < A[j + 1]) {
j++;
}
if (r >= A[j]) {
break;
}
//大的元素上移
A[s] = A[j];
s = j;
}
//赋值到调整后的节点
A[s] = r;
}

但是题目中的样例给的是从0开始的数组,所以要另外找规律,发现,原来length/2 现在成了,length(奇数) :(length-3)/2  length(偶数):(length-2)/2,但是没有通过。

错误代码:(目前不知道怎么改。)

void HeapAdjust(int *A,int s,int m) {
//s为当前需要调整的点,m为最后一个节点的下标
int r = A[s];
for (int j = 2 * s + 1 ;j <= m;j=j*2+1) {
if (j < m && A[j] < A[j + 1]) {
j++;
}
if (r >= A[j]) {
break;
}
//大的元素上移
A[s] = A[j];
s = j;
}
//赋值到调整后的节点
A[s] = r;


}
    
    
    int* heapSort(int* A, int n) {
        // write code here
        int start = 0;
if (n % 2 == 0) {
start = (n - 2) / 2;
}
else {
start = (n - 3) / 2;
}

for (int i = start;i >=0;i--) {
HeapAdjust(A,i,n-1);
        }

for (int i = n - 1; i > 1;i--) {
int t = A[1];
A[1] = A[i];
A[i] = t;
HeapAdjust(A,0,i-1);
}
        return A;
    }


希尔排序:有步长的插入排序;

void ShellInsert(int *A,int step,int lena) {


for (int i = step , j=0;i < lena;i++) {
if (A[i] < A[i - step]) {
int t = A[i];
for (j = i - step;j >= 0 && A[j] > t;j = j - step) {
A[j + step] = A[j];
}
A[j + step] = t;
}
}
}
    
    int* shellSort(int* A, int n) {
        // write code here
        int steps[] = {5,3,1};
for (int i = 0; i < 3;i++) {
ShellInsert(A,steps[i],n);
}
        return A;
    }



计数排序:

MAX-MIN是为了缩小范围,减少空间

int* countingSort(int* A, int n) {
        // write code here
            int min, max;
    if (n == 0 || n == 1) {
      return A;
    }
    min = A[0];
    max = A[0];
    for (int i = 0; i < n; i++) {
      if (A[i] < min) {
        min = A[i];
      }
      if (A[i] > max) {
        max = A[i];
      }
    }
    int count = max - min + 1;
    int counter[count];
    for (int i = 0; i < count; i++) {
      counter[i] = 0;
    }
    for(int i = 0; i < n; i++) {
      counter[A[i] - min]++;
    }
    int it = 0;
    for (int k = 0; k < count; k++) {
      while (counter[k]-- > 0) {
        A[it++] = k + min;
      }
    }
    return A;
    }


基数排序:先将所有数据按个位数字的大小放入排序容器,再按0~9容器从第一个元素开始重新输出,覆盖原数组,再按十位数字大小放入容器进行排序,此时同一容器中的数字是按个位递增的顺序进行排列的,以此类推,对于不满足位数要求的数字,mod时相当于在数字前面补0。

int getIndex(int number,int mod){
        
        number = number / (mod / 10);
        number = number %10;
        return number;
    }
    //所有元素只有个位时,直接排序
    void Sort(int *A,int n){
        
        for(int i = 0 ; i<n;i++){
            for(int j = 0 ; j < n -1-i;j++){
                
                if(A[j]>A[j+1]){
                    int t = A[j];
                    A[j] = A[j+1];
                    A[j+1] = t;
                }
                
            }
        }
        
    }
    

基数排序
    int* radixSort(int* A, int n) {
        // write code here
        int contain[10][n]; //排序容器
        int count[10];//记录每个容器有多少元素
        int max = 0;
        
        if(A == NULL|| n<2){
            return A;
        }
        
        //找到最大 数
        for (int i = 0 ;i<n;i++){
            if(A[i] > max){
                max = A[i];
            }
        }
        int mod = 10,flag1;
        //找到最大数的位数
        for(int i = 1;i<10;i++){
            if(max%mod==0){
                flag1 = i-1;
                break;
            }
            else{
                mod = mod * 10;
            }
        }
        //全是个位数
        if(flag1 == 0){
            //直接排序
            
            Sort(A,n);
            
            return A;
        }
        else{
            mod = 1;
            for(int i = 0 ; i<flag1;i++){
                mod = mod * 10;
                for(int j = 0;j<n;j++){
                    int index = getIndex(A[j],mod);
                    contain[index][count[index]] = A[j];
                    count[index]++;
                }
                int number = 0;
                for(int j = 0 ;j<10;j++){
                    for(int k = 0 ; k<count[j];k++){                        
                        A[number] = contain[j][k];
                        number++;


                    }
                }               
            }
            return A;
        }
    }


基数排序参考答案(含负数样例处理):

public static void radixSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int negNum = 0; // arr÷–∏∫ ˝µƒ∏ˆ ˝
        for (int i = 0; i < arr.length; i++) {
            negNum += arr[i] < 0 ? 1 : 0;
        }
        int[] negArr = new int[negNum];
        int[] posArr = new int[arr.length - negNum];
        int negi = 0;
        int posi = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < 0) {
                negArr[negi++] = -arr[i];
            } else {
                posArr[posi++] = arr[i];
            }
        }
        radixSortForPositive(negArr);
        radixSortForPositive(posArr);
        int index = 0;
        for (int i = negArr.length - 1; i >= 0; i--) {
            arr[index++] = -negArr[i];
        }
        for (int i = 0; i < posArr.length; i++) {
            arr[index++] = posArr[i];
        }
    }
 
    
    public static void radixSortForPositive(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        ArrayList<LinkedList<Integer>> qArr1 = new ArrayList<LinkedList<Integer>>();
        ArrayList<LinkedList<Integer>> qArr2 = new ArrayList<LinkedList<Integer>>();
        for (int i = 0; i < 10; i++) {
            qArr1.add(new LinkedList<Integer>());
            qArr2.add(new LinkedList<Integer>());
        }
        for (int i = 0; i < arr.length; i++) {
            qArr1.get(arr[i] % 10).offer(arr[i]);
        }
        long base = 10;
        while (base <= Integer.MAX_VALUE) {
            for (int i = 0; i < 10; i++) {
                LinkedList<Integer> queue = qArr1.get(i);
                while (!queue.isEmpty()) {
                    int value = queue.poll();
                    qArr2.get((int) (value / base) % 10).offer(value);
                }
            }
            ArrayList<LinkedList<Integer>> tmp = qArr1;
            qArr1 = qArr2;
            qArr2 = tmp;
            base *= 10;
        }
        int index = 0;
        for (int i = 0; i < 10; i++) {
            LinkedList<Integer> queue = qArr1.get(i);
            while (!queue.isEmpty()) {
                arr[index++] = queue.poll();
            }
        }
    }



空间复杂度:

O(1):插入排序,选择排序,冒泡排序,堆排序,希尔排序

O(logN)~O(N):快速排序

O(N):归并排序

O(M):基数排序,计数排序 。(M为你选择的用于排列的容器数量)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值