1 排序算法
1.1 冒泡排序
冒泡排序算法是最简单的排序算法,它的执行效率最低,但冒泡排序算法既适用于顺序物理结构也适用于链式物理结构。
void bubble_sort(int data[],size_t size){
int i,j;
for (i = 0;i < size - 1;i++){
int order = 1;//设置是否交换的变量,如果交换=0
for (j = 0;j < size - 1 - i;j++){
if (data[j] > data[j + 1]){
int temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
order = 0;//交换 置0
}
}
if (order) break;
}
}
1.2 选择排序
选择排序可以把数字直接放在最终位置,以位置为中心。
冒泡排序任何时候比较的都是相邻的两个数,而选择排序是固定一个数字,拿它前面所有的数字和它比较。
选择排序有多种实现方法,选择排序也可以使用链式物理结构。
void select_sort(int data[],size_t size){
int i,j;
for (i = 0;i < size - 1;i++){
int min = i;//记录最小值的下标,从序列首元素开始
for (j = i + 1;j < size;j++){//循环确定序列的最小下标
if (data[j] < data[min])
min = j;
}
if (min != i){//如果最小下标不是序列首,交换
int temp = data[i];
data[i] = data[min];
data[min] = temp;
}
}
}
1.3 插入排序
插入排序假设前面的数字都已经排序完成了,每次把后面的一个数字插入到前面已经排序完成的数字序列中合适的位置上。
插入排序也可以采用链式物理结构。
void insert_sort(int data[],size_t size){
int i,j;
for (i = 1;i < size;i++){
int insert = data[i];
for (j = i;j > 0 && insert < data[j - 1];j--)
data[j] = data[j - 1];
data[j] = insert;
}
}
1.4 快速排序
快速排序每次把一个基准数字放在最后位置上(基准数字前面的数都比它小,后面的数都比它大),使用递归的方式实现。
void quick_sort(int data[],size_t left,size_t right){//快速
size_t p = (left + right) / 2;//取一半做基准
int pivot = data[p];//基准数据
size_t i = left,j = right;
while (i < j){
for (;!(i >= p || pivot < data[i]);i++){
//()中是停止移动的条件,!就是继续移动的条件
if (i < p){//找到了比基准大的数
data[p] = data[i];//移动
p = i;//p的位置和i重合
}
for (;!(j <= p || pivot > data[j]);j--);
if (j > p){
data[p] = data[j];
p = j;
}
}
data[p] = pivot;//基准数,放到了正确的位置
if ((p - left) > 1)//前面的数组元素个数大于1
quick_sort(data,left,p - 1);
if ((right - p) > 1)
quick_sort(data,p + 1,right);
}
}
下面代码是这些算法的其他实现方法:
/*排序练习*/
#include<stdio.h>
void maopao_sort(int *p_num,int size){
int loop = 0,pos = 0;
for (loop = size - 1;loop >= 1;loop--){
for (pos = 0;pos <= loop - 1;pos++){
if (*(p_num + pos) > *(p_num + pos + 1)){
int tmp = *(p_num + pos);
*(p_num + pos) = *(p_num + pos + 1);
*(p_num + pos + 1) = tmp;
}
}
}
}
void sel_sort(int *p_num,int size){
int loop = 0,pos = 0;
//外循环每次把最大数放在最后的位置上
for (loop = size-1;loop >= 1;loop--){
//内循环每次用一个数字和最后位置的数字比较大小
for (pos = 0;pos <= loop - 1;pos++){
if (*(p_num + pos) > *(p_num + loop)){
int tmp = *(p_num + pos);
*(p_num + pos) = *(p_num + loop);
*(p_num + loop) = tmp;
}
}
}
}
//选择排序的另一种实现方法,这种方法会减少交换次数,但需要多使用一个变量
void sel_sort1(int *p_num,int size){
int loop = 0,pos = 0,num;
for (loop = size - 1;loop >= 1;loop--){
num = 0;
for (pos = 1;pos <= loop;pos++){
if (*(p_num + num) < *(p_num + pos)){
num = pos;
}
}
if (num < loop){
int tmp = *(p_num + num);
*(p_num + num) = *(p_num + loop);
*(p_num + loop) = tmp;
}
}
}
//插入排序
void insert_sort(int *p_num,int size){
int loop = 0,pos = 0,num = 0;
//每次外循环把下标为loop的数字插入到前面的数组中
for (loop = 1;loop <= size - 1;loop++){
//每次内循环找到插入位置
num = *(p_num + loop);
for (pos = loop - 1;pos >= 0;pos--){
if (*(p_num + pos) > num){
*(p_num + pos + 1) = *(p_num + pos);
}
else {
break;
}
}
*(p_num + pos + 1) = num;//注意,这里加1呀
}
}
//快速排序
void quick_sort(int *p_num,int size){
if (size > 0){//注意,这个条件很重要,递归结束条件
int *p_start = p_num;
int *p_end = p_num + size - 1;
int num = *p_start;
while (p_end > p_start){
if (*p_start > *p_end){
int tmp = *p_start;
*p_start = *p_end;
*p_end = tmp;
}
if (*p_start != num){
p_start++;
}
else {
p_end--;
}
}
quick_sort(p_num,p_start - p_num);
quick_sort(p_end + 1,p_num + size - 1 - p_end);
}
}
int main(){
int i = 0;
int num[] = {34,16,29,54,82,71,5,13};
maopao_sort(num,8);
//sel_sort(num,8);
//sel_sort1(num,8);
//insert_sort(num,8);
//quick_sort(num,8);
for (i = 0;i <= 7;i++){
printf("%d ",num[i]);
}
printf("\n");
return 0;
}
1.5 归并排序
归并排序假设所有数据分成两组,每组都是已经排序好的。每次从两组数据中找出各自最小的并选择更小的那个转移到另外一个数组中,当所有数据都转移完成后排序结束。把新数组中所有数字按顺序转移回原数组。
在进行归并之前先针对两组数字递归调用归并排序函数。
实现一:
void outer_merge(int data1[],size_t size1,int data2[],size_t size2,int data3[]){
//合并有序数组
int i = 0,j = 0,k = 0;
for (;k < size1 + size2;k++){
if (i < size1 && j < size2){//需要选择一个放入(比较)
if (data1[i] < data2[j]){
data3[k] = data1[i++];
}
else
data3[k] = data2[j++];
}
else{//只能从一个数据源放入(不比较值)
if (i < size1)
data3[k] = data1[i++];
else if(j < size2)
data3[k] = data2[j++];
}
}
}
void inner_merge(int data[],size_t left,size_t mid,size_t right){
//数组由2个有序的字数组组成
size_t size = (right - left + 1) * sizeof(data[0]);
int *temp = malloc(size);
outer_merge(data + left,mid - left + 1,data + mid + 1,right - mid,temp);//temp有序
memcpy(data + left,temp,size);
free(temp);
}
void merge_sort(int data[],size_t left,size_t right){
//归并排序(数组开始无序)
if (left < right){
int mid = (left + right) / 2;
merge_sort(data,left,mid);//排序mid之前
merge_sort(data,mid + 1,right);//排序mid之后
inner_merge(data,left,mid,right);
}
}
实现二:
void merge_sort(int *p_value,int *p_tmp,int start,int end){
if (end > start){
int mid = (start + end) / 2 + 1;
merge_sort(p_value,p_temp,start,mid - 1);
merge_sort(p_value,p_temp,mid,end);
int first = start,second = mid,temp = start;
while (first < mid || second <= end){
if (first == mid){
*(p_temp + temp) = *(p_value + second);
second++;
}
else if (second > end){
*(p_temp + temp) = *(p_value + first);
first++;
}
else {
if (*(p_value + first) > *(p_value +
second)){
*(p_temp + temp) = *(p_value + second);
second++;
}
else {
*(p_temp + temp) = *(p_value + first);
first++;
}
}
temp++;
}
int pos = 0;
for (pos = start;pos <= end;pos++){
*(p_value + pos) = *(p_temp + pos);
}
}
}
2 查找算法
折半查找算法要求数组本身是排序好的,折半查找算法每次可以排除掉一半的数字,采用了递归的方法。折半查找法不适合采用链式物理结构。
/*查找算法练习*/
#include<stdio.h>
int search(int *p_num,int size,int num){
int pos = 0;
for (pos = 0;pos <= size - 1;pos++){
if (*(p_num + pos) == num){
return pos;
}
}
}
//折半查找函数
int half_search(int *p_num,int size,int num){
if (size > 0){
if (*(p_num + size / 2) == num){
return size / 2;
}
else if (*(p_num + size / 2) > num){
return half_search(p_num,size / 2,num);
}
else {
return half_search(p_num + size / 2 + 1,size -
size / 2 - 1,num) + size / 2 + 1;
}
}
else {
return -1;
}
}
int main(){
//int num[] = {6,9,3,2,10,7,8};
int num[] = {1,2,3,4,5,6,7,8};
printf("数字7的下标是%d\n",half_search(num,8,7));
return 0;
}