排序(插入,希尔,选择,堆排序,归并,快排)

     《数论相关》那篇里最后提到的那道题——回文字符串,应该很多同学都会做吧,不过在这还是班门弄斧说一下思路:

假设有n个字符的字符串中有m1个字符n1,m2个字符n2,...mk个字符nk,则,m1 + m2 + ... + mk = n 且 m1,m2,...,mk中只能有1个奇数。这n个字符的字符串可以组合成的回文字符串个数,即转换成对m1/2个n1,m2/2个n2,...,mk/2个nk的全排列个数(n/2)!/(m1/2)!(m2/2)!...(mk/2)! (上篇博文提示1),根据提示2,将(n/2)!/(m1/2)!(m2/2)!...(mk/2)!的每一个阶乘均表示成不大于n/2的所有素数的阶乘积的形式则阶乘的除法即转换成减法。

      本篇总结一下学过的基础排序算法,只给出伪代码(自己亲手写出的代码才是自己的):

1.插入排序

直接插入排序    

定义:在长度为n的数列中,将第i个元素与第0~(i-1)个元素(已排序)从右到左依次比较,插入到合适的位置,使第0~i个元素也有序(0<= i < n)。算法导论中的     一个非常形象的比喻,从牌堆中一张一张抓牌,将抓到的牌,与手中已排好的牌从右到左依次比较,插到正确的位置。
算法复杂度:O(n^2)
    伪代码:
    insert_sort(A)
     for j = 2 to A.length
        key = A[j]
        i = j - 1
       while i > 0 && A[i] > key
           A[i+1] = A[i];
           i = i - 1
       A[i + 1] = key

希尔排序

定义:先将整个数列分割成若干个子数列分别进行直接插入排序,待整个数列中的记录"基本有序"时,再对全体记录进行一次直接插入排序,适用于部分有序的数列。
子数列的分割原则:
1.将相隔某个增量的元素组成一个子序列
2.每次设定的增量递减直到最后为1,并且增量序列的值必须互质
3.增量序列的取得方法尚未求出
部分有序:
1.每个元素距离它的最终位置不远
2.一个有序大数组接一个小数组
3.数组中只有几个元素的位置不正确

2.选择排序

简单选择排序

定义:在长度为n的数列中,从(n - i + 1)个数中选出最大(最小)的数与第i个数交换(1<= i <= n)
算法复杂度:O(n^2)
伪代码:
select_sort(A)
  for i = 1 to A.length
    l = i;
    for j = i to (n - i + 1)
        if A[j] > A[l]
            l = j
    exchange i and l

堆排序
 改进的选择排序算法,利用一种叫“堆”的数据结构进行信息管理。堆不仅用在堆排序中,也可以构造一种有效的优先的队列(应用很多,如共享计算机系统的作业调度)。
堆(二叉堆)
定义:是一个数组,可以被看成是一个近似的完全二叉树,树上每一个节点依层次分别对应数组的一个元素。
最大(小)堆 / 大(小)顶堆:除根节点外所有节点的父节点都不比自身小(大)
堆的操作(最大堆):
1.堆维护:当数组中某个位置index的元素不满足其所在的堆的性质时(该元素的值小于其子元素),需要将该元素与子节点中最大的交换位置,再以交换后的位置                              index1递归次过程,直到不需要与子节点交换位置为止
  伪代码:
        max_heapify(A, i)
l_child = 2i
r_child = 2i + 1
largest = i;
if l_child <= A.length && A[l_child] > A[i]
    largest = l_child
if r_child <= A.length && A[r_child] > A[largest]
    largest = r_child
if (largest != i)
    exchange A[largest] with A[i]
    max_heapify(A, largest]
2.建堆:可以通过1.堆维护,将长度为n的数组A转换成最大堆,因为子数组(A[n/2 + 1]~A[n])都是树的叶子节点,可以看成只有1个元素的大顶堆,则可以依次对 元素                   A[n/2]~A[1]依次调用堆维护,则可以生成一个最大堆
  伪代码:
       build_max_heap(A)
           for i = A.length / 2  to 1
           max_heapify (A, i)
堆排序
定义:利用以上两个堆的操作即可完成排序算法。在长度为n的数列中,先建好堆,循环以下两步:
    1.取出根元素,将最后一个叶子结点放入根节点位置
    2.对根节点做堆维护
算法复杂度:O(nlgn)
伪代码:
         heap_sort(A)
build_max_heap(A)
for i = A.length to 2
    exchange A[i] with A[1]
    copy A[A.length] to A[A.length - 1]
    max_heapify(A[length - 1], 1)
优先队列
同样是利用堆的数据结构,根据关键字的优先级存储关键字,应支持以下操作:
1. insert(S, key):关键字插入
2. maximum(S):返回优先级最大关键字
3.extract_maximum(S):取得优先级最大关键字并将其从队列中去除

3.归并排序

定义:将两个或两个以上的有序表组合成一个新的有序表
算法复杂度:O(nlgn)
伪代码:递归实现的两路归并排序
        merge_sort(A, s, e)
if s < e
mid = s + (e - s)>> 1;
merge_sort(A, s, mid)
merge_sort(A,mid + 1, e)
merge(A, s , mid, e)
        merge(A, s, mid, e)
tmp = int[e-s+1]
for i = s, j = mid + 1 to mid, e
     if A[i] > A[j] tmp[k++] = A[j++]
    else tmp[k++] = A[i++]
while i <= mid tmp[k++] = A[i++]
while j <= e tmp[k++] = A[j++]
A[s,e] = tmp[0,e-s]

4.快速排序

定义:从数列A[p,q]中任意选取一个值作为pivot(支点),将数列划分为两个子数列A[p,r],A[r+1,q],使得A[p,r]的所有元素均小于pivot,而A[r+1,q]的所有元素均大于                       pivot,然后对分成的两个子数列递归调用此过程
算法复杂度:O(nlgn)
伪代码:
        quick_sort(A,p,q)
if p < q
r = partition(A,p, q)
quick_sort(A,p,r-1)
quick_sort(A,r+1,q)
1.常见的两头扫描实现partition
        partition(A,low,high)
pivot = A[low]
while low < high
    while low < high &&  A[high] >= pivot high--
    A[low] = A[high]
    while low < high && A[low] <= pivot low++
A[high ] = A[low ]
A[low] = pivot
return low
2.单头扫描实现partition(循环里的判断是:如果碰到一个小于pivot的元素,则把该元素与第一个大于pivot的元素元素进行交换)
partition(A,low,high)
pivot = A[high]
i = low -1
for j = low to high - 1
    if A[j] <= pivot
        i = i + 1
        exchange A[i] with A[j]
exchange A[i+1] with A[high]
return i+1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是C语言实现各种排序方法的代码示例: 1. 冒泡排序 ``` c void bubble_sort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } ``` 2. 选择排序 ``` c void selection_sort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { int min_index = i; for (int j = i + 1; j < n; j++) { if (arr[j] < arr[min_index]) { min_index = j; } } int temp = arr[i]; arr[i] = arr[min_index]; arr[min_index] = temp; } } ``` 3. 插入排序 ``` c void insertion_sort(int arr[], int n) { for (int i = 1; i < n; i++) { int key = arr[i]; int j = i - 1; while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } ``` 4. 希尔排序 ``` c void shell_sort(int arr[], int n) { for (int gap = n / 2; gap > 0; gap /= 2) { for (int i = gap; i < n; i++) { int temp = arr[i]; int j; for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) { arr[j] = arr[j - gap]; } arr[j] = temp; } } } ``` 5. 快速排序 ``` c void quick_sort(int arr[], int left, int right) { if (left < right) { int pivot = partition(arr, left, right); quick_sort(arr, left, pivot - 1); quick_sort(arr, pivot + 1, right); } } int partition(int arr[], int left, int right) { int pivot = arr[right]; int i = left - 1; for (int j = left; j < right; j++) { if (arr[j] < pivot) { i++; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } int temp = arr[i + 1]; arr[i + 1] = arr[right]; arr[right] = temp; return i + 1; } ``` 6. 归并排序 ``` c void merge_sort(int arr[], int left, int right) { if (left < right) { int mid = left + (right - left) / 2; merge_sort(arr, left, mid); merge_sort(arr, mid + 1, right); merge(arr, left, mid, right); } } void merge(int arr[], int left, int mid, int right) { int i = left, j = mid + 1, k = 0; int temp[right - left + 1]; while (i <= mid && j <= right) { if (arr[i] < arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while (i <= mid) { temp[k++] = arr[i++]; } while (j <= right) { temp[k++] = arr[j++]; } for (int m = left, n = 0; m <= right; m++, n++) { arr[m] = temp[n]; } } ``` 7. 堆排序 ``` c void heap_sort(int arr[], int n) { for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } for (int i = n - 1; i > 0; i--) { int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; heapify(arr, i, 0); } } void heapify(int arr[], int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { int temp = arr[i]; arr[i] = arr[largest]; arr[largest] = temp; heapify(arr, n, largest); } } ``` 8. 计数排序 ``` c void counting_sort(int arr[], int n) { int max = arr[0], min = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) { max = arr[i]; } if (arr[i] < min) { min = arr[i]; } } int count[max - min + 1]; memset(count, 0, sizeof(count)); for (int i = 0; i < n; i++) { count[arr[i] - min]++; } for (int i = 1; i < max - min + 1; i++) { count[i] += count[i - 1]; } int temp[n]; for (int i = n - 1; i >= 0; i--) { temp[--count[arr[i] - min]] = arr[i]; } for (int i = 0; i < n; i++) { arr[i] = temp[i]; } } ``` 9. 桶排序 ``` c void bucket_sort(int arr[], int n) { int max = arr[0], min = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) { max = arr[i]; } if (arr[i] < min) { min = arr[i]; } } int bucket_num = (max - min) / n + 1; int bucket[bucket_num][n]; int bucket_count[bucket_num]; memset(bucket_count, 0, sizeof(bucket_count)); for (int i = 0; i < n; i++) { int index = (arr[i] - min) / n; bucket[index][bucket_count[index]] = arr[i]; bucket_count[index]++; } int k = 0; for (int i = 0; i < bucket_num; i++) { if (bucket_count[i] > 0) { insertion_sort(bucket[i], bucket_count[i]); for (int j = 0; j < bucket_count[i]; j++) { arr[k++] = bucket[i][j]; } } } } ``` 10. 基数排序 ``` c void radix_sort(int arr[], int n) { int max = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) { max = arr[i]; } } for (int exp = 1; max / exp > 0; exp *= 10) { counting_sort_by_digit(arr, n, exp); } } void counting_sort_by_digit(int arr[], int n, int exp) { int count[10]; memset(count, 0, sizeof(count)); for (int i = 0; i < n; i++) { count[(arr[i] / exp) % 10]++; } for (int i = 1; i < 10; i++) { count[i] += count[i - 1]; } int temp[n]; for (int i = n - 1; i >= 0; i--) { temp[--count[(arr[i] / exp) % 10]] = arr[i]; } for (int i = 0; i < n; i++) { arr[i] = temp[i]; } } ``` 以上是C语言实现各种排序方法的代码示例,可以根据具体的需求进行选择
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值