排序算法.

============================

壹.定义

1.稳定性:排序前后,数值相同的数据,它们的相对位置没有发生变化

2.内部排序:数据元素全部存放在内存中的排序

3.外部排序:先排序一部分,再进行合并

============================

贰.排序算法

在这里插入图片描述
计数排序

---------------------- 各种排序的时间,空间复杂度 -----------------------------------

在这里插入图片描述

一.插入排序

1.插入排序(在已经排好序的序列中插入一个新的)

void insertSort(int* arr, int n) {
	for (int i = 1;i < n;i++) {
		int cur = i - 1;
		int end = arr[i];
		//向前遍历,比较当前数和要插入的数,并寻找要插入的位置
		//在该位置后每个都向后推一个位置
		while (cur >= 0 && arr[cur] >= end) {
			arr[cur + 1] = arr[cur];
			--cur;
		}
		arr[cur + 1] = end;
	}
}

2.希尔排序(分组的插入排序)

void shellSort(int* arr,int n){
   int gap = n;
   while(gap > 1){
    gap = gap / 3 + 1;
    for(int i = gap;i < n;i++){
      int end = i - gap;
      int data = arr[i];
      while(end >= 0 && arr[end] >data){
       arr[end + gap] = arr[end];
       end -= gap;
      }
      arr[end + gap] = data;
    }
   }
}

二.选择排序

1.选择排序(挑最大/最小的放到数据的头部/尾部,两数据位置交换)

void selectSort(int* arr,int n){
int start = 0;
int i;
for(i = start + 1;i <= end;++i){
 if(arr[i] < arr[minIdx])
 minIdx = i;
} 
Swap(arr, start, minIdx);
++start;
}

2.堆排序

void shiftDown(int* arr,int n,int parent){
  int child = 2 * parent + 1;
  while(child < n){
     if(child + 1 < n && arr[child + 1] > arr[child])
     ++child;
     if(arr[child] > arr[parent]){
     swap(arr, child, parent);
     parent = child;
     chile = 2 * parent + 1;
     }
     else
     break;
  }
}

void heapSort(int* arr, int n){
 for(int i = (n - 2)/2;i >= 0;i--)
 shiftDown(arr, n, i);
 int end = n - 1;
 while(end > 0){
 swap(arr, end, 0);
 shiftDown(arr, end, 0);
 --end;
 }
}

三.交换排序

*1.冒泡排序

void bubbleSort(int* arr,int n){
  int end = n;
  while(end > 1){
    for(int i = 1;i < end;i++){
      swap(arr, i - 1, i);
    }
  }
  --end;
}

*2.快速排序

①horae法
  • 递增型
    选取一个基准值
    从剩余元素中开始遍历:
    1.从后往前找到第一个小于基准值的数据
    2.从前往后找到第一个大于基准值的数据
    3.交换找到的两个值
    4.从交换的位置,分别开始,继续执行第一步
    结束:用相遇位置的数据和基准值进行交换
//返回划分之后,基准值所在的位置
//未优化时,可能会导致栈溢出
int partion(int* arr,int begin,int end){
//选择基准值
  int key = arr[begin];
  int start = begin;
  while(begin < end){
    //从后向前先找小于基准值的位置
     while(arr[end] >= key)
     --end;
    //从前向后找大于基准值的位置
     while(arr[begin] <= key)
     ++begin;
     //交换
     Swap(arr, begin, end);
  }
  //交换基准值和相遇位置的数据
  Swap(arr, begin, end);
  return begin;
}

void quickSort(int* arr, int begin, int end){
  if(begin >= end)
  return;
  //div:一次划分之后,基准值位置
  int div = partion(arr,begin,end);
  //左右两部分进行快速排序
  //[begin, div - 1]
  //[div + 1, end]
  quickSort(arr,begin,div - 1);
  quickSort(arr,div + 1,end);
}
//优化
int getMid(int* arr, int begin, int end){
  int mid = begin + (end - begin) / 2;
  if(arr[begin] > arr[mid]{
    if(arr[mid] > arr[end])
       return mid;
    else if(arr[begin] >arr[end])  //mid end begin
       return end;
    else                          //mid begin end                                                      
       return begin;
  }
  else{
  //mid >= begin    begin mid
    if(arr[mid] < arr[end])
       return mid;
    else if(arr[begin] <arr[end])  //begin end mid
       return end;
    else                           //end begin mid
  }
}

int partion(int* arr,int begin,int end){
  int mid = getMid(arr, begin, end);
  Swap(arr, begin, mid);
  //选择基准值
  int key = arr[begin];
  int start = begin;
  while(begin < end){
    //从后向前先找小于基准值的位置
     while(arr[end] >= key)
     --end;
    //从前向后找大于基准值的位置
     while(arr[begin] <= key)
     ++begin;
     //交换
     Swap(arr, begin, end);
  }
  //交换基准值和相遇位置的数据
  Swap(arr, begin, end);
  return begin;
}

void quickSort(int* arr, int begin, int end){
  if(begin >= end)
  return;
  //div:一次划分之后,基准值位置
  int div = partion(arr,begin,end);
  //左右两部分进行快速排序
  //[begin, div - 1]
  //[div + 1, end]
  quickSort(arr,begin,div - 1);
  quickSort(arr,div + 1,end);
}
  • 递减型
    1.从后往前找到第一个大于基准值的数据
    2.从前往后找到第一个小于基准值的数据
②挖坑法
  • 递增型
    选取一个基准值
    从剩余元素中开始遍历:
    1.从后往前找到第一个小于基准值的数据,填到基准值的坑里(这个数据会产生一个新坑)
    2.从前往后找到第一个大于基准值的数据,填到新坑里(这个数据会产生一个新坑)
    3…从刚挖坑的位置,分别开始,继续执行第一步
    结束:用一开始的基准值填到相遇位置,返回基准值的位置
int getMid(int* arr, int begin, int end){
  int mid = begin + (end - begin) / 2;
  if(arr[begin] > arr[mid]{
    if(arr[mid] > arr[end])
       return mid;
    else if(arr[begin] >arr[end])  //mid end begin
       return end;
    else                          //mid begin end                                                      
       return begin;
  }
  else{
  //mid >= begin    begin mid
    if(arr[mid] < arr[end])
       return mid;
    else if(arr[begin] <arr[end])  //begin end mid
       return end;
    else                           //end begin mid
  }
}

int partion(int* arr,int begin,int end){
  int mid = getMid(arr, begin, end);
  Swap(arr, begin, mid);
  //选择基准值
  int key = arr[begin];
  while(begin < end){
    //从后向前先找小于基准值的位置
     while(arr[end] >= key)
     --end;
     //填坑
     arr[begin] = arr[end];
    //从前向后找大于基准值的位置
     while(arr[begin] <= key)
     ++begin;
     //填坑
     arr[end] = arr[begin];
  }
  arr[begin] = key;
  return begin;
}

void quickSort(int* arr, int begin, int end){
  if(begin >= end)
  return;
  //div:一次划分之后,基准值位置
  int div = partion(arr,begin,end);
  //左右两部分进行快速排序
  //[begin, div - 1]
  //[div + 1, end]
  quickSort(arr,begin,div - 1);
  quickSort(arr,div + 1,end);
}
  • 递减型
③前后指针法
  • prev-----上一个小于基准值的位置(从key开始)
  • cur-----下一个小于基准值的位置

当cur走到一个小于基准值的位置,则:
判断prev和cur是否连续:

  • 如果连续,区间[prev, cur]的值都是不大于基准值(更新prev, cur)
    
  • 如果不连续,区间[prev, cur]的值,有大于基准值的(更新prev,数据交换,更新cur)
    
数据交换:这时,用prev的下一个数和cur的数进行交换,然后prev和cur继续向后遍历
//一次划分
int partion(){
  //上一个小于基准值的位置
  int prev = begin;
  //下一个大于基准值的位置
  int cur = begin + 1;
  int key = arr[begin];
  while(cur <= end){
    //当cur走到下一个小于基准值的位置,判断prev和cur是否连续
    if(arr[cur] < key && ++prev != cur){
    //不连续,交换数据: prev cur
    Swap(arr, prev, cur);
    }
    ++cur;
  }
  Swap(arr, begin, prev);
  return prev;
}
//小区间优化-----小区间使用插入排序
void quickSort(int* arr, int begin, int end){
  if(begin >= end)
  return;
  if(end - begin < 10){
    insertSort(arr + begin, end - begin + 1);
  }
  //div:一次划分之后,基准值位置
  int div = partion(arr,begin,end);
  //左右两部分进行快速排序
  //[begin, div - 1]
  //[div + 1, end]
  quickSort(arr,begin,div - 1);
  quickSort(arr,div + 1,end);
}
④非递归快排
void quickSort(int* arr, int n){
  Queue q;
  initQueue(&q);
  //保存[0, n - 1]区间
  //队列,先进先出:先入左,再入右
  queuePush(&q, 0);
  queuePush(&q, n - 1);
  while(!queueEmpty(&q)){
     //取出一个区间的起始和结束位置
    int left = queueFront(&q);
    queuePop(&q);
    int right = queueFront(&q);
    queuePop(&q);
    //划分[left, right]
    int div = partion(arr, left, right);
    //子区间[left, div - 1]
    if(left < div - 1){
    queuePush(&q, left);
    queuePush(&q, div - 1);
    }
    //子区间[div - 1, right]
    if(div + 1 < right){
    queuePush(&q, div + 1);
    queuePush(&q, right);
  }
}
}

四.归并排序

1.归并排序

void mergeSort(int* arr, int n){
  int* step = (int*)malloc(sizeof(int) * n);
  //子序列的步长(自底向上的合并)
  int step = 1;
while(step < n){
  for(int idx = 0; idx < n; idx += 2 * step){
    //找到两个待合并的子序列区间
    //[begin, mid]     [mid + 1, end]
    int begin = idx;
    int mid = idx + step - 1;
    //判断是否存在第二个子序列
    if(mid >= n - 1)
    //不存在第二个子序列,直接跳过
    continue;
    int end = idx + 2 * step - 1;
    //判断第二个子序列是否越界
    if(end >= n)
    end = n - 1;
    merge(arr, begin, mid, end, tmp);
  }
  //更新步长
  step *= 2;
  }
}

============================

叁.不常见的排序

1.计数排序

时间复杂度:O(Max(n, range))
空间复杂度:O(range)

void countSort(in* arr, int n){
  //找到最大和最小值
  int max, min;
  min = max = arr[0];
  for(int i = 0; i < n;i++)[
    if(arr[i] > max)
    max = arr[i];
    if(arr[i] < min)
    min = arr[i];
  }
  //计算范围
  int range = max - min + 1;
  //创建一个计数数组,初始化为0
  int* countArr = (int*)calloc(range, sizeof(int));
  //计数
  for(int i = 0;i < range;i++){
    countArr[arr[i] - min]++;
  }
  //遍历计数数组,排序
  int idx = 0;
  for(int i = 0;i < range;i++){
    while(countArr[i] --){
    arr[idx++] = i + min;
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值