关闭

排序算法(一)

标签: 排序算法
507人阅读 评论(0) 收藏 举报
分类:

排序分为冒泡排序,选择排序,插入排序,希尔排序,合并排序,快速排序,堆排序等

等,本篇文章我来详细解析冒泡排序,选择排序,直接插入排序。

我们学会一种排序算法,只要是学会这种算法的思想,而不是单纯的记忆代码~~

(一)冒泡排序:

算法思想:通过一趟冒泡排序,将最大的元素放在最后一个位置(假如从小到大排序),

或者将最小的元素放在最后一个位置(假如从大到小排序)。下边我用图来解释这个思想



下边我来给出冒泡排序的代码(从小到大排序):

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
void bottle_sort(int arr[], int len)
{
	int i = 0;
	int j = 0;
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	for (i = 0;i < len - 1;i++)
	{
		for (j = 0;j < len - i - 1;j++)
		{
			
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			
			}
		}
	}
}
int main()
{
	int arr[5] = {5,6,3,2,1};
	int i = 0;
	bottle_sort(arr,5);
	for (i = 0;i < 5;i++)
	{
		printf("%d ",arr[i]);
	}
	system("pause");
	return 0;
}

这段代码是非常正确的代码,可以得到正确的结果。可是如果给出这样一组数据:2,9,8,7,6(同样要求从大到小排序),你还要比较4趟吗??第1趟比较完后,2就排在

最后,这组数据就已经有序了,所以,后边的几趟排序就是浪费时间~~下边我来给出优

化代码:(下边的代码只给出实现部分,测试部分省略)

<pre name="code" class="cpp">void bottle_sort(int arr[], int len)
{
	int i = 0;
	int j = 0;
	int flag = 0;
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	for (i = 0;i < len - 1;i++)
	{
        flag = 0;
		for (j = 0;j < len - i - 1;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}




这段代码就比前边那段代码好一点,如果我们发现某一趟就没有进行交换,我们就认为

排序结束,退出。具体实现办法:进入外层循环时,我们给flag置一个数,比如置0,如

果进入if语句,就改变flag的值。出了内层循环,如果flag的值还是0,说明内存没有进行

交换,此时外层循环也结束。

怎么感觉冒泡排序写成这样就已经很不错了。。是吗??其实还有改进得到空间,如果

我们记住上一趟最后一次交换的位置,这一趟的交换只需要排序这个位置之前的元素。

下边给出代码:

void bottle_sort(int arr[], int len)
{
	int i = 0;
	int j = 0;
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	int k = len - 1;
	int m = 0;
	for (i = 0;i < len - 1;i++)
	{
		for (j = 0;j < k;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
				m = j;
			}//找到每一趟最后一次交换的位置
		}
		k = m;
	}
}


代码简析:借助临时变量记住最后一次交换的位置,作为内层循环的边界。

要是把第2种和第3种方法结合起来,是不是更好呢~~~这里不给出代码了。
以上代码给出的是对整形数的排序,可是,如果要排序浮点数,排序结构体,是不是又

要再写一个函数~~c语言中的回调函数可以帮我们这么做~~(之前关于回调函数已经整

理过,这里再给出代码~~)

int compare(const void *elem1, const void *elem2)  
{  
    return *(const int *)elem1 - *(const int *)elem2;  
}  
void sort(void *base, unsigned int num,  
 unsigned int byte, int(*cmp)(const void *elem1, const void *elem2))  
{  
    char *pbase = (char *)base;  
    int flag = 0;  
    int i = 0;  
    int j = 0;  
    int k = 0;  
    const void *p1 = NULL;  
    const void *p2 = NULL;  
    for (i = 0;i < num - 1;i++)  
    {  
        flag = 0;  
        for (j = 0;j < num - 1 - i;j++)  
        {  
            p1 = (const void *)(pbase + j*byte);  
            p2 = (const void *)(pbase + (j + 1)*byte);  
            int ret = cmp(p1, p2);  
            if (ret > 0)  
            {  
                for (k = 0;k < byte;k++)  
                {//交换秘诀  
                    pbase[j*byte + k] = pbase[j*byte + k] + pbase[(j + 1)*byte + k];  
                    pbase[(j + 1)*byte + k] = pbase[j*byte + k] - pbase[(j + 1)*byte + k];  
                    pbase[j*byte + k] = pbase[j*byte + k] - pbase[(j + 1)*byte + k];  
                }  
                flag = 1;  
            }  
            if (flag == 0)  
                break;  
        }  
    }  
}  
int main()  
{  
    int(*cmp)(const void *elem1, const void *elem2) = compare;  
    int arr[4] = { 6,7,4,2 };  
    int i = 0;  
    sort(arr,4,4,cmp);  
    for (i = 0;i < 4;i++)  
    {  
        printf("%d ",arr[i]);  
    }  
    system("pause");  
    return 0;  
}  


如果有问题,可以指出哈~~

(二)选择排序

算法思想:选择最大的元素或最小的元素放在它应该出现的位置。这句话你可能并不太

清楚,下边图解:



下边给出实现代码:

void select_sort(int arr[], int len)
{
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int min = 0;//保存固定范围的最小值得下标
	for (i = 0;i < len - 1;i++)
	{
		min = i;
		for (j = i + 1;j < len;j++)
		{
			if (arr[j] < arr[min])
			{
				min = j;
			}
		}
		if (i != min)//如果这个位置放的不是最小数,需要交换
		{
			int tmp = arr[i];
			arr[i] = arr[min];
			arr[min] = tmp;
		}
	}
}


i控制的是找到的最小元素放的位置,j控制的是找最小元的范围(图片中 绿色竖线后

边)。

(三)直接插入排序:

算法思想:将要处理的元素放在前边有序元素的合适的位置。图解:



下边给出实现代码:

void insert_sort(int arr[], int len)
{
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int tmp = 0;
	int k = 0;
	for (i = 1;i < len;i++)
	{
		tmp = arr[i];
		for (j = i - 1;j >= 0;j--)
		{
			if (arr[j] <= arr[i])
				break;
		}
		for (k = i - 1;k > j;k--)
		{
			arr[k + 1] = arr[k];
		}
		arr[j+1] = tmp;
	}
}


tmp用来存储需要处理的数。内层第一个循环的作用是找出合适的位置,即就是找到比

当前要处理的元素小的第一个位置。(假设从小到大排序)。内层第二个循环的作用是

移动,将内层循环1找到的位置的下一个位置到要处理元素的位置之间的数据统一后移

一个,然后将要处理的元素放在内层循环1找到的位置的下一个位置。我们仔细看一下

就会发现内层的循环之间好像有一定的联系,能不能把两个循环合成一个呢~~

void insert_sort(int arr[], int len)
{
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int tmp = 0;
	for (i = 1;i < len;i++)
	{
		tmp = arr[i];
		for (j = i-1;(j >= 0) && (arr[j]>tmp);j--)//当要处理的元素比前边的元素小并且j还是大于等于0,
			//就要发生移位
		{
			arr[j+1] = arr[j];
		}//循环结束,j下标的元素是刚好小于要处理的元素(不满足arr[j]>tmp)或者是j=-1(不满足j>=0)
		arr[j + 1] = tmp;//将要处理的元素放在上次j的下一个位置
	}
}


其实在移位的环节,我们可以用交换来实现。给出一个简单的例子:比如2要放在3,4的

前边,即就是2与4交换,2再与3交换。下边我来用代码实现以下:

void insert_sort(int arr[], int len)
{
	if (len <= 0)
	{
		printf("数组长度不合理\n");
		exit(EXIT_FAILURE);
	}
	int i = 0;
	int j = 0;
	int tmp = 0;
	int m = 0;
	for (i = 1;i < len;i++)
	{
		tmp = arr[i];
		for (j = i - 1;(j >= 0) && (arr[j]>tmp);j--)
		{
			m = arr[j];
			arr[j] = arr[j + 1];
			arr[j + 1] = m;
		}
	}
}


上边这段代码,是用交换代替移位。下边我再给出图解,方便读者理解。



关于排序先整理这么多,之后再整理出其他的排序方法。以上如有不合理的地方,希望

指出~~


4
1

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:123504次
    • 积分:2939
    • 等级:
    • 排名:第12399名
    • 原创:158篇
    • 转载:3篇
    • 译文:0篇
    • 评论:54条
    个人专属
    博客专栏
    刷题

    文章:24篇

    阅读:9675
    linux学习

    文章:16篇

    阅读:10889
    c/c++

    文章:79篇

    阅读:71851
    最新评论