选择排序
选择排序(Selection sort)是一种简单直观的排序算法。 它的工作原理如下。 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。 以此类推,直到所有元素均排序完毕。
插入排序
插入排序(英语:Insertion Sort)是一种简单直观的排序算法。 它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
快速排序
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
除了以下代码的实现外,可以用C语言提供的qsort
函数进行快排。
步骤为:
1、从数列中挑出一个元素,称为“基准”(pivot),
2、重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分割结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作。
3、递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
4、递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
堆排序
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
第一行为排序前
第二行为排序后
889 520 613 737 121 501 83 919 35 629 891 387 117 549 235 218 182 49 535 884 30 848 242 589 758 576 311 46 571 982 328 633 461 217 892 821 365 640 630 758 830 552 652 305 154 714 469 150 840 941 630 463 333 336 247 400 906 307 825 176 20 694 123 671 889 305 886 312 17 494 733 121 531 764 753 576 467 206 516 889 192 44 620 933 610 479 235 781 699 970 228 879 261 352 656 840 981 785 715 899 903 249 800 601 947 338 708 857 510 224 505 778 467 693 297 343 995 687 407 946 451 55 248 860 446 228 231 955 626 255 306 829 311 767 895 501 893 640 763 596 597 416 916 33 139 986 421 836 394 815 154 751 785 345 653 78 349 577 40 401 951 148 556 303 919 898 666 229 801 176 903 800 271 646 885 279 831 922 256 277 335 166 454 693 638 528 411 750 748 641 859 273 469 961 329 385 105 937 184 139 112 744 616 661 5 226 596 780 640 797 337 321 504 798 865 444 489 52 761 651 274 571 584 772 698 324 297 90 709 395 338 685 345 282 358 237 894 684 656 207 741 275 169 417 591 910 140 779 130 37 912 814 560 271 230 274 704 167 795 994 193 2 904 499 564 484 857 70 34 532 26 873 390 549 456 732 907 758 847 650 897 596 344 759 628 325 470 562 398 249 969 931 719 933 10 854 378 488 576 192
2 5 10 17 20 26 30 33 34 35 37 40 44 46 49 52 55 70 78 83 90 105 112 117 121 121 123 130 139 139 140 148 150 154 154 166 167 169 176 176 182 184 192 192 193 206 207 217 218 224 226 228 228 229 230 231 235 235 237 242 247 248 249 249 255 256 261 271 271 273 274 274 275 277 279 282 297 297 303 305 305 306 307 311 311 312 321 324 325 328 329 333 335 336 337 338 338 343 344 345 345 349 352 358 365 378 385 387 390 394 395 398 400 401 407 411 416 417 421 444 446 451 454 456 461 463 467 467 469 469 470 479 484 488 489 494 499 501 501 504 505 510 516 520 528 531 532 535 549 549 552 556 560 562 564 571 571 576 576 576 577 584 589 591 596 596 596 597 601 610 613 616 620 626 628 629 630 630 633 638 640 640 640 641 646 650 651 652 653 656 656 661 666 671 684 685 687 693 693 694 698 699 704 708 709 714 715 719 732 733 737 741 744 748 750 751 753 758 758 758 759 761 763 764 767 772 778 779 780 781 785 785 795 797 798 800 800 801 814 815 821 825 829 830 831 836 840 840 847 848 854 857 857 859 860 865 873 879 884 885 886 889 889 889 891 892 893 894 895 897 898 899 903 903 904 906 907 910 912 916 919 919 922 931 933 933 937 941 946 947 951 955 961 969 970 981 982 986 994 995
请按任意键继续. . .
1、思路:先生成随机数,然后对生成的随机数进行排序。
以下分别是:选择排序 插入排序 快速排序 qsort实现快排 的函数(都经过测试,可以调用)
2、关于宏定义
#define SWAP(a,b) {int tmp;tmp=a;a=b;b=tmp;}
采用宏定义的方法实现的交换,因为该交换的使用频次过高,调用函数反而会因函数的压栈、弹栈增加了算法的执行时间,所以这里不用函数
#include
#include
#include
#define N 10000
#define SWAP(a,b) {int tmp;tmp=a;a=b;b=tmp;}
//打印
void arr_print(int *arr)
{
int i;
for (i = 0; i < N; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
//选择排序
void arr_select(int *arr)
{
int i, j, max_pos;
for (i = N; i > 0; i--)//最大的数放在最右边
{
max_pos = 0;
for (j = 1; j < i; j++)//找出左边剩余的i个数中最大的数
{
if (arr[max_pos] < arr[j])
{
max_pos = j;
}
}
SWAP(arr[max_pos], arr[i - 1]);//最大的数交换到右边
}
}
//插入排序
void arr_insert(int *arr)
{
int i, j, k, insert_val;
for (i = 1; i < N; i++)//外层控制对哪个数进行插入(从arr[0]到arr[i-1]是有序的)
{
for (j = 0; j < i; j++)//内层控制寻找插入位置
{
if (arr[i] < arr[j])//发现插入位置
{
insert_val = arr[i];
for (k = i - 1; k >= j; k--)//从插入点开始的数全部向右移
{
arr[k + 1] = arr[k];
}
arr[j] = insert_val;
break;
}
}
}
}
//快速排序
int partition(int *arr, int left, int right)
{
int i, k;
k = left;//k是游标,k=left用来表示比末尾数小的起始位置,注意不能写成k=0
for (i = left; i < right; i++)//递归用left和right控制边界
{
if (arr[right] > arr[i])
{
SWAP(arr[k], arr[i]);
k++;
}
}
SWAP(arr[k], arr[right]);//把分界线换到中间
return k;
}
void arr_quick(int *arr, int left, int right)
{
int pivot;//分割
if (left < right)
{
pivot = partition(arr, left, right);//递归,返回值为分界线
arr_quick(arr, left, pivot - 1);//排左边
arr_quick(arr, pivot + 1, right);//排右边
}
}
//用qsort实现快排
int compare(const int *left, const int *right)//要有自己写的排序规则
{
if (*left > *right)
{
return 1;
}
else if (*left == *right)
{
return 0;
}
else return -1;
}
//堆排序:运用二叉树的思想(将数的大小分层级)对一位数组进行排序
void heap_max(int *arr, int start, int end)//end控制边界,防止son访问越界
{
int dad = start;
int son = 2 * dad + 1;
while (son < end)//控制边界,防止son访问越界
{
if (son + 1 < end&&arr[son] < arr[son + 1])
{
son++;
}
if (arr[dad] > arr[son])
{
return;
}
else
{
SWAP(arr[dad], arr[son]);
dad = son;//交换之后,考虑下一级别的大小关系是否因为本次交换而发生了改变
son = 2 * dad + 1;
}
}
}
void arr_heap(int *arr)
{
int i;
for (i = N / 2 - 1; i >= 0; i--)//变成大顶堆(把最大的元素放到根部),2/N-1是最后一个父节点所在的位置
{
heap_max(arr, i, N);
}
SWAP(arr[0], arr[N - 1]);//根元素放到数组最后一个元素
for (i = N - 1; i > 0; i--)//把后N-1个元素分别用大顶堆的方式排好
{
heap_max(arr, 0, i);//重新调为大顶堆(把最大的元素放到根部),只需要将根部元素a[0]进行heap_max操作,就能重新让根部元素成为最大元素,因为节点是分层级的
SWAP(arr[0], arr[i - 1]);//根元素放到数组最后一个元素
}
}
int main()
{
// int a[N];
int *a = (int*)calloc(N, sizeof(int));//动态申请,防止数组需要的空间超过1M爆栈
int i;
srand(time(NULL));
for (i = 0; i < N; i++)//生成随机数
{
a[i] = rand() % 1000;
}
arr_print(a);//排序前
// arr_select(a);//选择排序
// arr_insert(a);//插入排序
// arr_quick(a, 0, N - 1);//快速排序
// qsort(a, N, sizeof(int), compare);//数组名,元素个数,元素大小,自己写的排序规则
arr_heap(a);
arr_print(a);//排序后
system("pause");
}