데이터 구조 --- 공통 정렬 및 빠른 정렬 (C 언어)

일반적으로 사용되는 정렬

버블 정렬

버블 정렬 알고리즘 아이디어

  • 배열의 머리 부터 시작하여 인접한 두 요소의 크기를 지속적으로 비교 하고 더 큰 요소가 배열이 끝날 때까지 점차 뒤로 이동 (두 요소의 값 교환)하도록합니다. 첫 번째 비교 후 가장 큰 요소를 찾아 마지막 위치로 이동할 수 있습니다.
  • 첫 번째 라운드가 끝나면 두 번째 라운드를 계속합니다. 비교 는 여전히 배열의 선두 에서 이루어지며, 더 큰 요소는 배열의 마지막에서 두 번째 요소까지 점차 뒤로 이동합니다. 두 번째 비교 후 다음으로 큰 요소 를 찾아 두 번째 위치에 배치 할 수 있습니다 .
  • 비유로 ** n-1 (n은 배열의 길이) ** 라운드 "버블 링"을 수행 한 후 모든 요소를 ​​정렬 할 수 있습니다.

버블 정렬 C 언어 구현

#include <stdio.h>

int main(){
    
    

    int nums[10] = {
    
    4, 5, 2, 10, 7, 1, 8, 3, 6, 9};
    int i, j, temp, isSorted;

    //优化算法:最多进行 n-1 轮比较

    for(i=0; i<10-1; i++){
    
    

        isSorted = 1; //假设剩下的元素已经排序好了

        for(j=0; j<10-1-i; j++){
    
    

            if(nums[j] > nums[j+1]){
    
    

                temp = nums[j];

                nums[j] = nums[j+1];

                nums[j+1] = temp;

                isSorted = 0; //一旦需要交换数组元素,就说明剩下的元素没有排序好

            }

        }

        if(isSorted) break; //如果没有发生交换,说明剩下的元素已经排序好了
}

    for(i=0; i<10; i++){
    
    

        printf("%d ", nums[i]);
    }

    printf("\n");

    return 0;
}

삽입 정렬

단순 삽입 정렬 알고리즘의 원리

  • 정렬 할 전체 순번에서 요소를 선택 하고 이미 정렬 된 하위 순번에 삽입하여 요소 1을 더한 순서가 지정된 하위 순번을 얻습니다. 전체 순번에 삽입 될 요소가 0이 될 때까지 전체 순번이 모두 정렬됩니다. .

실제 알고리즘에서는 시퀀스의 첫 번째 요소를 순서가 지정된 시퀀스로 선택하는 경우가 많으며 (요소가 확실히 정렬되어 있기 때문에) 전체 시퀀스가 ​​정렬 될 때까지 이전 순서가 지정된 시퀀스에 다음 요소를 점차적으로 삽입합니다. .

회로도는 다음과 같습니다.
여기에 사진 설명 삽입

정렬 코드 구현 삽입 :

#include <stdio.h>

/*
直接插入排序:
    直接插入排序就是从待排序列中选出一个元素,插入到已经有序的元素之中,直到所有的元素都插入到有序序列中所有的元素就全部
有序了。
    通常的做法就是将第一个元素看做是有序的元素(即待排序列的第一个元素看做是有序序列),然后我们将第二个元素和有序序列(即
第一个元素)作比较,按正确的序列插入到序列中去。然后在将第三个元素和前面有序序列(即整个待排序列的前两个元素)作比较,将第
三个插入到前两个元素中去,使得前三个元素有序。以此类推,直到所有的元素都有序。
*/

void insertSort(int *arr[],int len);

int main(int argc, char *argv[])
{
    
    
    int arr[5]={
    
    
        3,89,72,43,1
    };
    insertSort(arr,5);
    int i;
    for(i=0;i<5;i++){
    
    
        printf("%d ",arr[i]);
    }
    return 0;
}

/*
简单插入排序函数
*/
void insertSort(int *arr[],int len){
    
    
    int i;
    int j;
    int temp;  //定义一个临时变量,用于交换数据时存储
    for(i=1;i<len;i++){
    
      //因为我们要对该待排序列的每一个元素都和前面的已排好序的序列进行插入,所以我们会对序列进行遍历
        for(j=0;j<i;j++){
    
      //第二层循环主要用于对已排好序的序列进行扫描,和要插入进来的数据进行逐一比较,然后决定插入到哪里
            if(arr[j]>arr[i]){
    
    //从前往后对已排好序的元素和待插入元素进行大小比较,然后直到找到一个元素比被插入元素大,则交换位置
                temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }
    }
}

정렬 선택

선택 정렬 알고리즘의 원리

  • 선택 정렬은 간단하고 직관적 인 정렬 알고리즘입니다. 버블 정렬과 매우 유사 하며 n-1 라운드를 비교합니다. 각 라운드는 n–1–i 번을 비교하고 각 라운드는 최대 또는 최소 값을 찾습니다.
  • 그러나 버블 정렬은 각 라운드에서 찾은 가장 높은 값을 맨 오른쪽에 배치하고 선택적 정렬은 각 라운드에서 찾은 가장 높은 값을 맨 왼쪽에 배치합니다. 그리고 알고리즘에서 버블 정렬은 인접한 숫자를 하나씩 비교하는 것입니다. 예를 들어 작은 것부터 큰 것까지 정렬하는 것입니다. 앞이 뒤보다 크면 가장 큰 숫자가 떠오를 때까지 두 숫자를 교환합니다. "맨 오른쪽 등. 선택 정렬은 첫 번째 요소의 아래 첨자를 먼저 저장 한 다음 모든 후속 숫자를 첫 번째 요소와 차례로 비교하는 것입니다. 더 작은 숫자가 발견되면 더 작은 숫자의 아래 첨자가 기록 된 후 다음 모든 숫자가 기록됩니다. 가장 작은 숫자의 아래 첨자를 찾을 때까지 숫자를 차례로 작은 숫자와 비교 한 다음 숫자를 맨 왼쪽에 배치합니다. 즉, 아래 첨자가 0 인 숫자가 서로 바뀝니다. 가장 작은 숫자의 아래 첨자가 0이면 스왑 할 필요가 없습니다.
  • 따라서 선택 정렬 알고리즘은 먼저 가장 작은 숫자의 첨자가 0인지 여부를 결정하는 것입니다. 그렇지 않으면 가장 작은 숫자가 첫 번째 요소가 아니라는 의미입니다. 그런 다음 숫자가 첫 번째 요소와 교환되어 라운드에서 가장 작은 숫자가됩니다. 그 번호가 발견되어 맨 왼쪽에 배치되었습니다.
  • 두 번째 라운드에서는 새 시퀀스의 두 번째 요소의 아래 첨자도 저장되고 이후의 모든 번호가 두 번째 요소와 차례로 비교됩니다. 더 작은 숫자가 발견되면 더 작은 숫자의 아래 첨자가 기록되고 다음 모든 번호가 의 숫자는 가장 작은 숫자가 끝에서 발견 될 때까지 더 작은 숫자와 순차적으로 비교되며 가장 작은 숫자는 전체 시퀀스에서 "두 번째로 작은"숫자입니다. 그런 다음이 숫자의 아래 첨자가 1과 같은지 판단하고, 1이 아니면 "두 번째로 작은"숫자가 두 번째 요소가 아니라는 것을 의미하며,이 숫자는 두 번째 요소와 교환되므로 두 번째 라운드 후에, "두 번째로 작은"숫자를 찾아 두 번째 위치에 놓습니다. 전체 시퀀스가 ​​작은 것에서 큰 순서로 정렬 될 때까지이 방법을 반복하십시오.
  • 가장 큰 숫자에서 가장 작은 숫자로 정렬 된 경우 가장 큰 숫자의 아래 첨자를 기록하고 각 라운드에서 가장 큰 숫자를 찾아 왼쪽에 놓습니다.

정렬 알고리즘 구현 선택 :

# include <stdio.h>
int main(void)
{
    
    
    int i, j;  //循环变量
    int MinIndex;  //保存最小的值的下标
    int buf;  //互换数据时的临时变量
    int a[] = {
    
    5, 5, 3, 7, 4, 2, 5, 4, 9, 1, 8, 6};
    int n = sizeof(a) / sizeof(a[0]);  //存放数组a中元素的个数
    for (i=0; i<n-1; ++i)  //n个数比较n-1轮
    {
    
    
        MinIndex = i;
        for (j=i+1; j<n; ++j)  //每轮比较n-1-i次, 找本轮最小数的下标
        {
    
    
            if (a[MinIndex] > a[j])
            {
    
    
                MinIndex = j;  //保存小的数的下标
            }
        }
        if (MinIndex != i)  /*找到最小数之后如果它的下标不是i则说明它不在最左边, 则互换位置*/
        {
    
    
            buf = a[MinIndex];
            a[MinIndex] = a[i];
            a[i] = buf;
        }
    }
    printf("最终排序结果为:\n");
    for (i=0; i<12; ++i)
    {
    
    
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

병합 정렬

병합 정렬 알고리즘의 원리 :

  • (Merge Sort)는 병합 연산을 기반으로하는 효과적인 정렬 알고리즘으로 분할 및 정복 방법 (Divide and Conquer)을 사용하는 매우 일반적인 응용 프로그램입니다. 기존의 정렬 된 하위 시퀀스를 결합하여 완전히 정렬 된 시퀀스를 얻습니다. 즉, 먼저 각 하위 시퀀스를 순서대로 만든 다음 하위 시퀀스를 순서대로 만듭니다. 두 개의 정렬 된 목록이 하나의 정렬 된 목록으로 병합되는 경우 사용 시간을 위해 공간을 희생하는 알고리즘 인 양방향 병합이라고합니다.

다음은 재 인쇄 된 소스 에서 가져온 것입니다 .
병합 알고리즘 :

병합 알고리즘의 핵심 단계는 다음과 같습니다.

  • 분해하다
  • 병합

여기에 사진 설명 삽입

  • 병합 정렬은 정렬 할 요소 시퀀스의 초기 입력 상태에 의존하지 않기 때문에 두 하위 시퀀스의 길이는 기본적으로 분할 될 때마다 동일하므로 병합 정렬이 최고이고 최악최악의 평균 시간 복잡도는 O (n * log2 ^ n)입니다. ), 안정적인 정렬 알고리즘입니다.
  • 소규모 하위 배열을 처리하기 위해 삽입 정렬을 사용 하는 병합 정렬 최적화는 일반적으로 병합 정렬 실행 시간을 10 % ~ 15 % 단축 할 수 있습니다.

병합 알고리즘 구현 (C 언어)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
 
//分组归并
void _Merge(int *a, int begin1, int end1, int begin2, int end2, int *tmp)
{
    
    
	int index = begin1;
	int i = begin1, j = begin2;
	//注意:当划分的区间足够小时,begin1==end1,begin2==end2
	while (i <= end1&&j <= end2){
    
    
		if (a[i]<=a[j])
			tmp[index++] = a[i++];
		else
			tmp[index++] = a[j++];
	}
	//将左边元素填充到tmp中
	while (i <= end1)
		tmp[index++] = a[i++];
	//将右边元素填充的tmp中
	while (j <= end2)
		tmp[index++] = a[j++];
	//将tmp中的数据拷贝到原数组对应的序列区间
	//注意:end2-begin1+1
	memcpy(a + begin1, tmp + begin1, sizeof(int)*(end2 - begin1 + 1));
}
//归并排序
void MergeSort(int *a, int left, int right, int *tmp)
{
    
    
	if (left >= right)
		return;
	assert(a);
	//mid将数组二分
	int mid = left + ((right - left) >> 1);
	//左边归并排序,使得左子序列有序
	MergeSort(a, left, mid, tmp);
	//右边归并排序,使得右子序列有序
	MergeSort(a, mid + 1, right, tmp);
	//将两个有序子数组合并
	_Merge(a, left, mid, mid + 1, right, tmp);
}
//打印数组
void PrintArray(int *a, int len)
{
    
    
	assert(a);
	for (int i = 0; i < len; i++)
		printf("%d ", a[i]);
	printf("\n");
}
int main()
{
    
    
	int a[] = {
    
     10, 6, 7, 1, 3, 9, 4, 2 };
	int *tmp = (int *)malloc(sizeof(int)*(sizeof(a) / sizeof(int)));
	memset(tmp, -1, sizeof(a) / sizeof(int));
	MergeSort(a, 0, sizeof(a) / sizeof(int)-1, tmp);
	PrintArray(a, sizeof(a) / sizeof(int));
	system("pause");
	return 0;
}

빠른 정렬

빠른 정렬 알고리즘 아이디어 :

  • 먼저 요소의 특정 위치를 찾고 데이터를 두 부분으로 나눕니다.
  • 왼쪽에있는 것은 일반적으로 위의 방법을 기반으로 하며 요소의 특정 위치를 찾은 다음 두 부분으로 나눌 수도 있습니다.
  • 비유하면 재귀 적 사고를 사용하여 첫 번째 요소가 마침내 발견됩니다.
    여기에 사진 설명 삽입

빠른 정렬 구현 :

#include <stdio.h>
#include <stdlib.h>

int FindPos(int * a,int low,int high)
{
    
    
    int val = a[low];

    while(low < high)
    {
    
    
        while(low < high && a[high] <= val)
            --high;
        a[low] = a[high];

        while(low < high && a[low] <= val)
            ++low;
        a[high] = a[low];
    } //终止while循环之后,low和high一定是相等的
    a[low] = val;

    return low;   //low可以改为high,返回的是位置
}

void QuickSort(int * a,int low,int high)
{
    
    
    int pos;
    if(low < high)
    {
    
    
        pos = FindPos(a,low,high);
        QuickSort(a,low,pos-1);
        QuickSort(a,pos+1,high);
    }
}

int main()
{
    
    
    int a[6] = {
    
    -2,1,0,5,4,3};
    int i;
    QuickSort(a,0,5);   //第二个参数表示第一个元素的下标  第三个参数表示最后一个元素的下标
    for(i = 0; i < 6; ++i)
    {
    
    
        printf("%d",a[i]);
    }

    printf("\n");
    return 0;
}

추천

출처blog.csdn.net/qq_41782149/article/details/93378947