C语言一一字符串排序、冒泡排序、选择排序、二分查找

前言

如果你没有扎实的数据结构的功底,不知道链表与队列、哈希表与二叉查找树使用等。不妨可以考虑从排序跟查找算法入手。

字符串排序
我们来处理一个按字母表顺序排序字符串的实际问题。比如说名单表、创建索引和许多其他情况下都会用到字符串排序。用strcmp()函数确定两个字符串的顺序。一般的做法是读取字符串函数、排序字符串并打印出来。现在来实现读入字符串,并排序字符串:

#include <stdio.h>
#include <string.h>//strcmp

#define SIZE 81  //限制输入的字符串长度
#define LEN 20 //读入的最多行数

void StringSort(char *str[], int num);
void StringShow(char *str[], int num);
char *s_gets(char *str, int num);

int main(int argc, char const *argv[])
{
	char *pstr[LEN]; //内含指针变量的数组
	char input[LEN][SIZE]; //储存输入的数组
	int ct = 0; //输入计数

	printf("Input up to %d lines,and I will sort them.\n",LEN );
	printf("To stop,press the Enter key at a line's start.\n");

	while (ct < LEN && s_gets(input[ct],SIZE) != NULL && input[ct][0] != '\0')
	{
		pstr[ct] = input[ct]; //设置指针指向字符串
		ct++;
	}

	StringSort(pstr, ct);
	StringShow(pstr, ct);
	return 0;
}

//字符串排序
void StringSort(char *str[], int num)
{
	int i = 0,j = 0;
	char *temp = NULL;

	for (i = 0; i < num -1; i++)
	{
		for (j = i+1; j < num; j++)
		{
			if (strcmp(str[i],str[j]) > 0)
			{
				temp = str[i];
				str[i] = str[j];
				str[j] = temp;
			}
		}
	}

}

//打印字符串
void StringShow(char *str[], int num)
{
	int i = 0;
	puts("Here is the sorted list:\n");
	for (i = 0; i < num; i++)
		puts(str[i]); //排序后的指针

}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;

    ret_val = fgets(st, n, stdin);
    if (ret_val != NULL)
    {
        find = strchr(st, '\n');
        if (find != NULL)
            *find = '\0';
        else
            while(getchar() != '\n')
                continue;
    }

    return ret_val;
}

输出结果:
在这里插入图片描述
该程序的巧妙之处在于排序的是指向字符串指针,而不是字符串本身。pstr[ct] = input[ct]; 这意味着指针pstr[i]指向数组input[i]的首字符。每个input[i]都是一个内含81个元素的数组。

如无必要不用排序字符串,所以程序使用临时储存区(input)数组获取用户输入的字符串。如果用户通过键盘模拟EOF或输入一行空行,将退出下面的循环:

	while (ct < LEN && s_gets(input[ct],SIZE) != NULL && input[ct][0] != '\0')

冒泡排序
我们最熟悉不过的就是冒泡排序,经常的在面试题中出现。冒泡排序重复地走访过要排序的数列,一次比较两个相邻的元素,如果第一个比第二个大,就交换他们两个。

#include <stdio.h>

void BubbleSort (int arr[], int len) ;
void BubbleShow(int arr[],int len);

int main(int argc, char const *argv[])
{
	int arr[] = { 11, 21, 13, 2, 56, 12, 67, 78, 37, 9, 56, 6, 90, 43 };
    int len = (int) sizeof(arr) / sizeof(*arr); 

    BubbleSort (arr, len);
    BubbleShow(arr,len);

	return 0;
}

void BubbleSort (int arr[], int len) 
{
    int i = 0;
    int j = 0;
    int temp = 0;
    for ( i = 0; i < len - 1; i++) 
    {
        // 每趟 i 循环将最大(小)值固定到最后一位
        for ( j = 0; j < len - 1 - i; j++) 
        {
            // 每趟 j 循环循环没有被固定到后方的数字
            if (arr[j] > arr[j + 1]) 
            {
                // arr[j] < arr[j + 1] 代表从小到大排序
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

void BubbleShow(int arr[],int len)
{
	int i = 0;

	puts("Here is the sorted list:\n");
	for ( i = 0; i < len; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}

输出结果:
在这里插入图片描述
从程序来看,整个冒泡排序就是通过两个嵌套循环,外层循环将此轮最大(小)值固定到此轮尾部,内层循环比较相邻的两个元素并决定是否交换位置。

选择排序

选择排序首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。接下来看看代码是怎么实现的。

#include <stdio.h>

void SelectSort(int arr[], int len);
void swap(int *a, int *b);
void SelectShow(int arr[],int len);


int main(int argc, char const *argv[])
{
	int arr[] = { 11, 21, 13, 2, 56, 12, 67, 78, 37, 9, 56, 6, 90, 43 };
    int len = (int) sizeof(arr) / sizeof(*arr); 

    SelectSort (arr, len);
    SelectShow(arr,len);

	
	return 0;
}

void SelectSort(int arr[], int len)
{
	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;//记录最小值
		}

		swap(&arr[min],&arr[i]);
	}
}

void swap(int *a, int *b)
{
	int temp = 0;
	temp = *a;
	*a = *b;
	*b = temp;
}

void SelectShow(int arr[],int len)
{
	int i = 0;

	puts("Here is the sorted list:\n");
	for ( i = 0; i < len; i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}

输出结果:
在这里插入图片描述
顺便一提。C库中有一个更高级的排序函数:qsort()。该函数使用一个指向函数的指针进行排序比较。

二分查找
二分查找,也称折半查找,在某些情况下相比于顺序查找(链表、队列),使用折半查找算法的效率更高。但是该算法的使用的前提是静态查找表中的数据必须是有序的。

在学习二叉查找树之前,必须要先了解一些名词,我们借助下面的图来了解:

在这里插入图片描述

介绍树的基本名词:

1.根节点:数字56节点没有父节点,我们把它称为根节点。
2.父节点:如数字19节点的父节点为数字56节点。
3.子节点:在图中,根节点56有两个孩子,分别是19,80,它们都是56的子节点.
4.叶子节点:513377592等节点,它们没有子节点,因此是叶子节点。

二叉查找树是一种树的特殊形式,它的每个节点最多两个孩子节点,分别为左孩子和右孩子。而二叉查找树在此基础上,还有一个特点,就是每个节点比它左子树的节点值都要大,而比右子树的节点值都要小。 下面通代码实现二分查找树:

#include <stdio.h>

int bin_search( int arr[], int len, int key ); //二分查找

int main(int argc,char **argv)
{
        int arr[] = {5,13,19,21,37,56,64,75,80,88,92};
        int num = 0, addr = 0;
        int len = (int) sizeof(arr) / sizeof(*arr); 

        printf("The number information searched is(5,13,19,21,37,56,64,75,80,88,92)\n");
        printf("Please enter the number to be searched: ");
        scanf("%d", &num);

        addr = bin_search(arr, len, num);
        if( addr != -1)
        {
                printf("Find the number %d ,location : %d\n", num, addr);
        }
        else
        {
                printf("Can't find!\n");
        }

        return 0;
}

//二分查找
int bin_search( int arr[], int len, int key )
{
        int left, right, mid;
        
        left = 0;
        right = len-1;

        while( left <= right )
        {
                mid = (left+right)/2;
                if( arr[mid] == key )//找到
                {
                        return mid;                // 查找成功
                }

                if( arr[mid] < key ) //从左子树查找
                {
                        left = mid + 1;        // 在后半序列中查找
                }

                if( arr[mid] > key ) //从右边子树查找
                {
                        right = mid - 1;        // 在前半序列中查找
                }
        }

        return -1;                                // 查找失败,最后一层还没有找到
}

输出结果:
在这里插入图片描述通过二分查找的平均查找长度,相比顺序查找来说,明显二分查找的效率要高。

发布了71 篇原创文章 · 获赞 42 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chen1415886044/article/details/102670284