Linux C语言程序设计(六)——查找与排序

1、算法的概念

        算法( Algorithm) 是将一组输入转化成一组输出的一系列计算步骤,其中每个步骤必须能在有限时间内完成。算法是用来解决一类计算问题的,注意是一类问题,而不是一个特定的问题。

       这里我们可以回想之前提到的递归算法,递归就是算法,而具体求解的过程,不能称为算法,而是算法实现的过程。


2、插入排序

        插入排序算法类似于玩扑克时抓牌的过程,玩家每拿到一张牌都要插入到手中已有的牌里,使之从小到大排好序。

        模拟一下我们的扑克牌的整理牌的过程,现在抓到一张7,把它和手里的牌从右到左依次比较, 7比10小,应该再往左插, 7比5大,好,就插这里。为什么比较了10和5就可以确定7的位置?为什么不用再比较左边的4和2呢?因为这里有一个重要的前提:手里的牌已经是排好序的。现在我插了7之后,手里的牌仍然是排好序的,下次再抓到的牌还可以用这个方法插入。

#include <stdio.h>
#define LEN 5
int a[LEN] = { 10, 5, 2, 4, 7 };
void insertion_sort(void)
{
	int i, j, key;
	for (j = 1; j < LEN; ++j) {
		printf("%d, %d, %d, %d, %d\n",
		a[0], a[1], a[2], a[3], a[4]);
		key = a[j];
		i = j - 1;
		while (i >= 0 && a[i] > key) {
			a[i+1] = a[i];
			--i;
		}
		a[i+1] = key;
	}
	printf("%d, %d, %d, %d, %d\n",
	a[0], a[1], a[2], a[3], a[4]);
}
int main(void)
{
	insertion_sort();
	return 0;
}

3、归并排序

       插入排序算法采取增量式( Incremental) 的策略解决问题,每次添一个元素到已排序的子序列中,逐渐将整个数组排序完毕,它的时间复杂度是Θ(n2)。下面介绍另一个典型的排序算法——归并排序,它采取分而治之( Divide-and-Conquer) 的策略,时间复杂度是Θ(nlgn),优于插入排序算法。归并排序的步骤如下:

1)把长度为n的输入序列分成两个长度为n/2的子序列。

2)对这两个子序列分别采用归并排序。

3)将两个排序好的子序列合并成一个最终的排序序列。

在描述归并排序的步骤时又调用了归并排序本身,可见这是一个递归的过程。

#include <stdio.h>
#define LEN 8
int a[LEN] = { 5, 2, 4, 7, 1, 3, 2, 6 };
void merge(int start, int mid, int end)
{
	int n1 = mid - start + 1;
	int n2 = end - mid;
	int left[n1], right[n2];
	int i, j, k;
	for (i = 0; i < n1; i++) {/* left holdsa[start..mid] */
		left[i] = a[start+i];
	}
		
	for (j = 0; j < n2; ++j){ /* right holdsa[mid+1..end] */
		right[j] = a[mid+1+j];
	}


	i = j = 0;
	for (k = start; i < n1 && j < n2; ++k) {
		if (left[i] < right[j]) {
			a[k] = left[i];
			++i;
			} else {
			a[k] = right[j];
			++j;
			}
		}
		if (i < n1) /* left[] is notexhausted */
			for (; i < n1; i++) {
				a[k] = left[i];
				++k;
			}
		if (j < n2) /* right[] is notexhausted */
			for (; j < n2; ++j) {
				a[k] = right[j];
				++k;
			}
		}


void sort(int start, int end)
{
	int mid;
	if (start < end) {
		mid = (start + end) / 2;
		printf("sort (%d-%d, %d-%d) %d %d %d %d %d %d %d %d\n",start, mid, mid+1, end,a[0], a[1], a[2], a[3], a[4],a[5], a[6], a[7]);
		sort(start, mid);
		sort(mid + 1, end);
		merge(start, mid, end);
		printf("merge (%d-%d, %d-%d) to %d %d %d %d %d %d %d %d\n",start, mid, mid+1, end,a[0], a[1], a[2], a[3], a[4],a[5], a[6], a[7]);
	}
}


int main(void)
{
	sort(0, LEN-1);
	return 0;
}

4、线性查找

线性查找比较简单,一个一个从前往后找就行了。如下的一段代码:

#include <stdio.h>
char a[]="hello world";
int indexof(char letter)
{
	int i = 0;
	while (a[i] != '\0') {
		if (a[i] == letter)
			return i;
		i++;
	}
	return -1;
}
int main(void)
{
	printf("%d %d\n", indexof('o'), indexof('z'));
	return 0;
}

5、折半查找

        折半查找针对的是已经有序的带查找字符串。

        由于这个序列已经从小到大排好序了,每次取中间的元素和待查找的元素比较,如果中间的元素比待查找的元素小,就说明“如果待查找的元素存在,一定位于序列的后半部分”,这样可以把搜索范围缩小到后半部分,然后再次使用这种算法迭代。这种“每次将搜索范围缩小一半”的思想称为折半查找:

#include <stdio.h>
#define LEN 8
int a[LEN] = { 1, 3, 3, 3, 4, 5, 6, 7 };
int binarysearch(int number)
{
	int mid, start = 0, end = LEN - 1;
	while (start <= end) {
		mid = (start + end) / 2;
		if (a[mid] < number)
			start = mid + 1;
		else if (a[mid] > number)
			end = mid - 1;
		else
			return mid;
	}
	return -1;
}
int main(void)
{
	printf("%d\n", binarysearch(3));
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值