排序与查找——Linux C编程一站式学习

算法的概念

算法是将一组输入转化成一组输出的一系列计算步骤,其中每个步骤必须能在有限时间内完成。
算法是用来解决一类计算问题的方法,具有通用性。

插入排序

插入排序采取增量式的策略,它的时间复杂度是O(n的平方)。类似于玩扑克,玩家每拿到一张牌都要插入到手中已有的牌里,使之从小到大排好序。
在对数组进行插入排序时,要将插入点之后的数据依次往后移动一个单元。代码如下

#include <iostream>
using namespace std;
#define N 5
int a[N] = { 10, 5, 2, 4, 7 };
void insertion_sort()
{
 int i, j, key;
 for (j = 1; j < N; j++) 
 {
 	cout<<a[0]<<a[1]<<a[2]<<a[3]<<a[4]<<endl;
 	key = a[j];
 	i = j - 1;
 	while (i >= 0 && a[i] > key) 
 	{
 		a[i+1] = a[i];
 		i--;
 	}
 	a[i+1] = key;
  	}
  	cout<<a[0]<<a[1]<<a[2]<<a[3]<<a[4]<<endl;
 }
int main(void)
{
	insertion_sort();
	return 0;
}

算法的时间复杂度分析

评价算法的好坏,一个重要的标准就是算法的时间复杂度。
在分析算法的时间复杂度时,我们更关心最坏情况而不是最好情况,理由如下:

  1. 最坏情况给出了算法执行时间的上界,我们可以确信,无论给什么输入,算法的执行时间都不会超过这个上界,这样为比较和分析提供了便利。
  2. 对于某些算法,最坏情况是最常发生的情况,例如在数据库中查找某个信息的算法,最坏情况就是数据库中根本不存在该信息,都找遍了也没有,而某些应用场合经常要查找一个信息在数据库中存在不存在。
  3. 虽然最坏情况是一种悲观估计,但是对于很多问题,平均情况和最坏情况的时间复杂度差不多,比如插入排序这个例子,平均情况和最坏情况的时间复杂度都是输入长度n的二次函数

归并排序

归并排序,它采取分而治之的策略,时间复杂度是O(nlgn)。
归并排序的步骤:

  1. Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。
  2. Conquer: 对这两个子序列分别采用归并排序。
  3. Combine: 将两个排序好的子序列合并成一个最终的排序序列。

#include <iostream>
#include <algorithm>
using namespace std;
int arr[1001];
 
void merge_sort(int mi, int mj)
{
    if(mi == mj) return;
    merge_sort(mi, (mi + mj)/2);
    merge_sort((mi + mj)/2 + 1, mj);
    int i = mi, j = (mi + mj)/2 + 1, arrt[1001];
    for(int k = mi; k <= mj; k++)
    {
        if(i <= (mi + mj)/2 && arr[i] <= arr[j] || j > mj) 
        	arrt[k] = arr[i++];
        else 
        	arrt[k] = arr[j++];
    }
    for(int k = mi; k <= mj; k++) 
    	arr[k] = arrt[k];
}
 
int main(){
    int n;
    cin >> n;
    for(int i = 0; i < n; i++) 
    	cin >> arr[i];
    merge_sort(0, n-1);
    for(int i = 0; i < n; i++) 
    	cout << arr[i] << " ";
    cout << endl;
}

线性查找

有些查找问题要用时间复杂度为O(n)的算法来解决。这个实现是最直观和最容易想到的,但它并不是最快的算法。

int indexof(char letter)
{
 	int i = 0;
 	while (a[i] != '\0') {
 	if (a[i] == letter)
 		return i;
 	i++;
 }
 return -1;
}

折半查找

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


#include<stdio.h>
#include<stdlib.h>
 
int binFind(int A[],int len,int x)   //折半查找
{
	if(A == NULL)
		exit(1);
	else
	{
		int low = 0,high = len-1;//low用来记录低下标,high用来记录高下标
		int mid;//low值为中间下标,用来与x比较(因此成为折半查找)
		while(low <= high)
		{
			mid = ((low + high)/2);
			if(A[mid]<x)//如果x大于中间值,则x一定在右半段
			{
				low = mid+1;//改变低下标为中间下标的下一个
				mid = (low + high)/2;
			}
			else if(A[mid]>x)//如果x小于中间值,x一定存在于左半段
			{
				high = mid-1;//改变高下标为中间下标的前一个
				mid = (low + high)/2;
			}
			else
				return mid;//否则,x与当前中间值相等,则返回中间下标
		}
	}
	return -1;
}
 
int main()
{
	int arr[] = {1,2,3,5,9,15,36,46,78,95};
	int ph = 0,item = 0;
	for(int i = 0;i<sizeof(arr)/sizeof(arr[0]);i++)
		printf("%d ",arr[i]);
	printf("\n请输入要查找的值:");
	scanf("%d",&item);
	ph = binFind(arr,sizeof(arr)/sizeof(arr[0]),item);
	if(-1 != ph)
		printf("a[%d] = %d\n",ph,arr[ph]);
	else
		printf("没有找到%d\n",item);
	return 0;
 
}

发布了39 篇原创文章 · 获赞 4 · 访问量 1123

猜你喜欢

转载自blog.csdn.net/qq_41403559/article/details/104281149