排序算法总结

########关于c++数组的理解
给定一个数组int array[10] = {9,8,7,10,6,1,0,'\0'};
可以直接用int length = sizeof(array)/sizeof(array[0]); 求得数组的长度,求得长度的操作一定要在数组被当做参数传递之前进行。
例如:如果通过一个求数组长度的函数来求数组长度
int getArrayLength(int array[])
{
  int length = sizeof(array)/sizeof(array[0]);
  //这样求得的length永远是2,sizeof(array)永远都是指针的大小,是8;
}

########插入排序的几种思想
1和2都是直接插入排序,时间复杂度有些区别
1.假设第一个数据是有序的,把之后的每个数据都和前面的数据比较,如果带插入数据比当前比较的数据小就交换位置
for(i; i<6-1; i++)
  {
    int j = i;
    while(array[j+1] < array[j] && j >= 0)
    {
      int temp = array[j];
      array[j] = array[j+1];
      array[j+1] = temp;
      j--;
    }
 }
2.把需要插入的数据拿出来放在旁边,然后把它和它前面的数据比较,比它大的数据,就往后一次移动一位,最后把带插入的数据放在空的位置上。
for(i; i<arrayLength-1; i++)
 {
   int j=i+1;
   int insertNum = array[j]; 
   while(j>0 && insertNum < array[j-1])
   {
     array[j] = array[j-1];
     j--;
   }
   array[j] = insertNum;
 }
3.二分法插入排序,通过二分法把需要插入位置,然后移动其它的数据,把它插到对应的位置
for (int i=1; i<array.length; i++) {
            temp = array[i];
            left = 0;//重点,必须在在for循环条件的内部,保证每一次都要在数组的最左端开始,否则无法排序
            right = i-1;
            while(left <= right) {//先找出需要插入的位置
                mid = (left+right)/2;
                if(temp < array[mid]) {//因为i的左边都是有序的,所以temp比中间的小,就会比mid到i之间的数字都小
                    right = mid -1;
                } else {
                    left = mid +1;
                }
            }
            //通过上面的while循环找到需要插入的数据,应该插入的位置,然后移动其他的数据,把temp插入到对应的位置上面
            for (int j=i-1; left<=j; j--) {//把temp插入到left的位置,j是比left要大的数字
                array[j+1] = array[j];
            }
            if(left != i) {
                array[left] = temp;
            }
}

for (i = 1; i<length; i++) {
            right = i-1;
            int temp = array[i];
            while (left <= right) {
                mid = (left+right)/2;
                if (temp < array[mid]) {
                    right = mid-1;
                } else {
                    left = mid  + 1;
                }
            }
            for (j=i-1; j>=left; j--) {
                array[j+1] = array[j];
            }
            array[left] = temp;
        }

4.希尔排序(https://blog.csdn.net/weixin_37818081/article/details/79202115)
希尔排序是插入排序的一种,希尔排序又叫做缩小增量排序,该方法的基本思想是:
假设一个元素序列有n个元素,首先取一个整数作为增量Hibbard,取增量的方式有多种,length/3+1,length/2等等,
然后把所有元素之间距离为Hibbard的元素放在同一个子序列中,直到Hibbard的值为1,将所有的元素放在同一个子序列为止。
int dk = length;
while(dk > 1)
{
  dk = dk/3 + 1;
  int i;
  for(i = dk; i<length; i++)
  {
    int temp = array[i];
    j = i-dk;// *******很重要,从第一个开始,如果是j=i的话很容易出错误
    while(j>=0 && array[j]>temp) //和*****temp****进行比较,比temp大的数都要往后移动到相应的位置,并不是交换
    {
      array[j+dk] = array[j];
      j -= dk;
    }
    array[j+dk] = temp;
  }
}


########选择排序
1.简单选择排序
原理,每一次都在数组中找出最小,或者最大的数,记住它的下标k,然后把它赋值给min或者max,然后先把最左边的插入位置的元素放到k位置,然后把min或者max放到最左边
for (int i=0; i<length; i++)
{
  int k = i;
  int min = array[i];
  for(int j=i; j<length-1; j++)
  {
    if(min > array[j+1]) //一点要和min进行比较,这样才能求得最小值, array[j] > array[j+1]; min = array[j+1]; 这样找不出最小值,是行不通的,一定要注意
    {
      min = array[j+1];
      k=j+1;
    }
  }  
  array[k] = array[i];
  array[i] = min;
}

2.复杂的选择排序,堆排序(https://www.cnblogs.com/chengxiao/p/6129630.html)
https://my.oschina.net/JKOPERA/blog/1927611
首先介绍一下节点的下标:i节点的父节点下标就为(i-1)/2,它的左右子节点下标分别为2*i+1和2*i+2;如第0个节点左右子节点下标分别为1和2。

调整堆function
void adjustHeap(int array[], int parent, int length){
  int temp = array[parent];
  int child = 2*parent +1;//先获得左孩子节点
  while(child < length){
    if(child+1<length && array[child]<array[child+1]){ //如果左节点的值小于右节点的值,就选中右节点
      child++;
    }
    if(temp >= array[child]){  //------------应该是temp 而不是 array[parent]
      break; //如果选中的节点比父节点小,就结束,不需要交换
    }
    
    //如果选中的节点,大于父节点,就把它赋值给父节点
    array[parent] = array[child];
    //然后以子节点作为父节点,调整下一个节点
    parent = child;
    child = 2*parent +1;
  }
  //最后把temp放到子节点最后停留的位置parent = child;
  array[parent] = temp;
}

//构建大顶堆&&交换堆顶与末尾的元素
void heap_Sort(int array[], int length){
  for(int i=length/2-1; i>=0; i--){ ----------------------------这个地方i一定是可以取到0的
    adjustHeap(array,i,length);
  }
  for(int i=length-1; i>0; i--){
    int temp = array[i];
    array[i] = array[0];
    array[0] = temp;
    
    //调整堆的结构,把最大值保存下来,得到i-1个元素的堆,把最大的数据保留下来,然后构建调整为大顶堆
    adjustHeap(array,0,i);
  }
}


########交换排序
1.冒泡排序
对整个数组进行遍历,把最大的元素通过交换的方式放在最后面,然后进行下一次遍历,找到最大,一次循环
for(int i=0; i<length-1; i++){
  for(int j=0; j<length-i-1; j++){
    if(array[j] > array[j+1]){
      int temp = array[j];
      array[j] = array[j+1];
      array[j+1] = temp;
    }
  }
}

2.快速排序
以数组中的一个元素为基准,调整数组的顺序,把比基准元素小的放在它左边,比它大的放在右边,记录最后基准元素的位置,然后分别给它的左边和右边进行之前相同的操作
然后依次递归,直到排序完成

int getMiddle(int a[], int low, int high)
    {
        int temp = a[low];// 基准元素
        while (low < high)
        {
            // 找到比基准元素小的元素位置
            while (low < high && a[high] >= temp)  一定要注意这个地方包含等号,相等的时候不移动
            {
                high--;
            }
            a[low] = a[high];
            while (low < high && a[low] <= temp)
            {
                low++;
            }
            a[high] = a[low];
        }
        a[low] = temp;
        return low;
    }

void quickSort(int a[], int low, int high){
        if (low < high)
        { // 如果不加这个判断递归会无法退出导致堆栈溢出异常
            int middle = getMiddle(a, low, high);
            quickSort(a, 0, middle - 1);
            quickSort(a, middle + 1, high);
        }
}

########归并排序
基本思想:归并排序是将两个或两个以上有序表合并成一个新的有序表,即把待排序列分为若干个子序列,每个子序列是有序的,然后再把有序的子序列合并为整体的有序序列
https://www.cnblogs.com/chengxiao/p/6194356.html

void merge(int arr[],int left,int mid,int right,int temp[]){
            int i = left;//左序列指针
            int j = mid+1;//右序列指针
            int t = 0;//临时数组指针
            while (i<=mid && j<=right){
                if(arr[i]<=arr[j]){
                    temp[t++] = arr[i++];
                }else {
                    temp[t++] = arr[j++];
                }
            }
            while(i<=mid){//将左边剩余元素填充进temp中
                temp[t++] = arr[i++];
            }
            while(j<=right){//将右序列剩余元素填充进temp中
                temp[t++] = arr[j++];
            }
            t = 0;
            //将temp中的元素全部拷贝到原数组中
            while(left <= right){
                arr[left++] = temp[t++];
            }
        }
        void sort(int arr[],int left,int right,int temp[]){
            if(left<right){
                int mid = (left+right)/2;
                sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
                sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
                merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
            }
        }

c语言
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j=midIndex+1, k = 0;
    while(i!=midIndex+1 && j!=endIndex+1)
    {
        if(sourceArr[i] > sourceArr[j])
            tempArr[k++] = sourceArr[j++];
        else
            tempArr[k++] = sourceArr[i++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];

   k = 0;
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[k++];
}
 
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}


########基数排序
https://www.cnblogs.com/kkun/archive/2011/11/23/2260275.html
https://baike.baidu.com/item/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F/7875498?fr=aladdin
LSD基数排序的基本步骤: (LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。)
1.找出数组中的最大的数,然后通过最大数的位数,判断再次分配的次数
2.求得每个元素个位十位百位的数是多少, 通过求余数把它们求出来,各位:(798/1) %10 = 8  十位: (798/10) %10 = 9 百位: (798/100) %10 = 7
3.然后首先通过个位数的数字,把元素放入到对应的桶中
4.然后把它们按桶的大小顺序,从小到大依次取出,现在的数个位数就是有序的了
5.然后再通过十位数的数字,把元素依次放入到对应的桶中,因为个位数已经是有序的了,现在十位数也是有序的了
如果没有百位数,就到此为止,取出所有的数据,就是已经排序完成了

////获取数组中的最大数

int getMaxNum(int array[], int length) {
    int maxNum = 0;
    for (int i=0; i<length; i++) {
        if (maxNum < array[i]) {
            maxNum = array[i];
        }
    }
    return maxNum;
}

//获取最大数的位数,次数也是再分配的次数。

int getLoopTimes(int maxNum) {
    int count = 1;
    int temp = maxNum / 10;
    while (temp != 0) {
        count ++;
        temp = temp / 10;
    }
    return count;
}

//将数字分配到各自的桶中,然后按照桶的顺序输出排序结果

void sort2(int array[], int length, int loop) {
//建立一组桶此处的20是预设的根据实际数情况修改
    int buckets[10][20] = {};

    //求桶的index的除数

    //如798个位桶index=(798/1)%10=8

    //十位桶index=(798/10)%10=9

    //百位桶index=(798/100)%10=7

    //tempNum为上式中的1、10、100

    int tempNum = 10^(loop- 1);
    for (int i=0; i<length; i++) {
        int throw_index = (array[i]/tempNum) % 10;
        for (int j=0; j<20; j++) {
            if (buckets[throw_index][j] == 0) {
                buckets[throw_index][j] = array[i];
                break;
            }
        }
    }
   //将桶中的数,倒回到原有数组中
    int k = 0;
    for (int i=0; i<10; i++) {
        for (int j=0; j<20; j++) {
            if (buckets[i][j] != 0) {
              array[k++] = buckets[i][j];
              buckets[i][j] = 0;
            }
        }
    }
}
void sort1(int array[], int length) {
    //取得最大的数
    int maxNum = getMaxNum(array, length);
    //根据最大数,计算出需要分配的次数
    int loopTimes = getLoopTimes(maxNum);
    //对每一位进行桶分配
    for (int i=1; i<=loopTimes; i++) {
        sort2(array, length, i);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值