데이터 구조 및 알고리즘 - 선택 및 버블, 빠른 정렬 및 계산

    1: 정렬 선택

    시나리오: 반에서 가장 키가 큰 사람을 어떻게 찾을 수 있나요? ABCDAB

선택 정렬의 개념은 삽입 정렬과 매우 유사하며, 정렬 간격과 비정렬 간격으로 나누어지기도 합니다. 그러나 선택 정렬은 매번 정렬되지 않은 범위에서 가장 작은 요소를 찾아 정렬된 범위의 끝에 배치합니다. 그러나 배열을 이동하는 삽입 정렬과 달리 선택 정렬은 다음 예와 같이 매번 교체됩니다.     

4 5 6 3 2 1

처음:     1 5 6 3 2 4

두 번째:     1 2 6 3 5 4

1. 시간 복잡도: O(N^2)

2. 공간 복잡도: O(n)

3.교환 횟수

4. 안정성: 불안정

   2: 버블 정렬

        핵심 아이디어: 버블 정렬은 인접한 두 데이터에만 작동합니다. 각 버블링 작업은 인접한 두 요소를 비교하여 크기 관계 요구 사항을 충족하는지 확인합니다. 만족스럽지 않으면 두 사람이 교환하도록 하십시오. 한 번의 버블링은 최소한 하나의 요소를 있어야 할 위치로 이동시키며, 이를 n번 반복하면 n개의 데이터 정렬이 완료됩니다.

        예: 4 5 6 3 2 1, 작은 것부터 큰 것 순으로 정렬됩니다. 1 2 3 4 5 6

정렬: 어떤 상황에서 교환이 필요하지 않습니까? 즉, 모든 숫자가 있어야 할 곳에 있습니다. O(n)

1. 시간 복잡도: O(n^2)

2. 공간 복잡도: O(n)

3. 교환 횟수 : 상당히 많음

4. 안정성: 안정

package Sort2;

import java.util.Arrays;

/**
 * 冒泡排序
 */

public class BubbleSort {

	public static void main(String[] args) {

		int data[] = { 4, 5, 6, 3, 2, 1 };
		int n = data.length;

		//n-1:这里是因为判断两个数是只比较一次 例如: 1  2   比较次数只会比一次
		for (int i = 0; i < n - 1; i++) {	//排序的次数
			//优化:如果所有的数都排好了,不需要交换了,就不需要冒泡了,所以直接退出
			boolean flag = false;
			// n-1-i:要减掉i是因为每次冒泡排序都会将后面的值确定,所以i就是后面已经排好的数字,所以就不需要再比较了,所以得减掉
			for (int j = 0; j < n - 1 - i; j++) {	//具体冒泡 n - 1 - i,6,5,4,3,2,1
				if (data[j] > data[j + 1]) {
					//交换
					int temp = data[j];	//用了第三个变量,不用第三个变量
					data[j] = data[j + 1];
					data[j + 1] = temp;
					flag = true;

					//异或实现
//					data[j] = data[j] ^ data[j+1];
//					data[j+1] = data[j] ^ data[j+1];
//					data[j] = data[j] ^ data[j+1];
				}
			}
			if(!flag) break;
		}
		System.out.println(Arrays.toString(data));
	}
}
/**
 * 下面是交换的时候如果不用第三方变量存储的话如何交换
 */
// a:2 b:3
// 3 2 => a:3 b:2
// 用加减
//a = a + b => a = 3+2 =5;
//b = a - b => b = 5-3 =2;
//a = a - b => a = 5-2 =3;
   2.1  간단한 최적화를 수행하는 방법:

                1. 교환 시 제3자 변수가 필요하며, 이는 공간을 차지하므로 XOR 교환을 사용할 수 있습니다.

                2. 정렬되면 계속 반복할 필요가 없으므로 플래그를 라벨로 추가합니다.

       2.2  XOR 교환을 구현하는 방법은 무엇입니까?

        XOR 연산이 두 숫자의 값을 교환할 수 있는 이유는 XOR 연산이 다음과 같은 속성을 갖고 있기 때문입니다.

  1. 숫자를 0과 XOR한 결과는 여전히 숫자 자체입니다. a ^ 0 = a
  2. 자신과 XOR된 숫자의 결과는 0입니다. a ^a = 0
  3. XOR 연산은 교환법칙(a ^b = b ^ a)을 만족하며 이러한 성질을 이용하여 XOR 연산을 통해 두 숫자의 값을 교환할 수 있으며 구체적인 단계는 다음과 같다. 초기값은 각각 a0과 b0에 대한 것입니다.
  4. 1단계: a를 b와 XOR하여 결과를 a에 저장합니다. a = a ^ b. 이때 a의 값은 a0^b0이고, b의 값은 그대로 유지된다.
  5. 2단계: a를 b와 XOR하고 결과를 b에 저장합니다. b = a ^ b. 이번 단계에서는 이전 단계에서 얻은 a(a0^b0)의 값을 b0과 XOR하면 결과는 a의 원래 값인 a0이 됩니다. 동시에 XOR 연산은 교환법칙을 만족하므로 b = (a0 ^ b0) ^ b0 = a0 ^ (b0 ^ b0) = a0 ^ 0 = a0이 됩니다. 이때 a의 값은 그대로 유지되고 b의 값은 a0이 된다.
  6. 3단계: 마지막으로 a와 b를 XOR하고 결과를 a에 저장합니다: a = a ^ b. 이번 단계에서는 이전 단계에서 얻은 a의 값 a0^b0과 이전 단계에서 얻은 b(a0)의 값을 XOR하여 결과는 b0이 됩니다.
public class SwapNumbers {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        
        System.out.println("交换前:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        
        // 使用异或操作交换a和b的值
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
        
        System.out.println("交换后:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

        세 번째: 빠른 정렬

45 28 80 90 50 16 100 10

기본 번호: 일반적으로 정렬할 순서의 첫 번째 번호입니다.

1차 정렬 베이스 번호: 45

밑수보다 작은 수를 뒤에서 앞으로 찾아 바꿔보세요: 10 28 80 90 50 16 100 45

앞에서 뒤로 기본 숫자보다 큰 것을 찾아 교환합니다: 10 28 45 90 50 16 100 80    

   10 28 16 90 50 45 100 80  

   10 28 16 45 50 90 100 80

기준수를 기준으로 3등분으로 나누면 왼쪽의 비율이 작아지고 오른쪽의 비율이 커집니다.

{10 28 16} 45 {50 90 100 80}

45비트 기본 번호를 사용한 정렬이 완료된 것은 이번이 처음입니다.

1. 시간 복잡도: nlogn, 최악의 경우는 O(n^2)

2. 공간 복잡도: O(n)

3. 안정성: 불안정

4. 퀵 정렬과 병합 비교:

(1) 병합정렬의 처리과정은 아래에서 위로 진행되며, 하위 문제를 먼저 처리한 후 병합한다.

(2) 퀵 정렬은 실제로 위에서 아래로, 먼저 분할한 다음 병합하지 않고 하위 문제를 처리하는 것입니다. 최적화는 벤치마크 수치를 최적화하고 세 수치 중 중간을 취하는 아이디어를 제공하는 것이다.

package Sort2;

public class QuiklySort {

	public static void qSort(int data[], int left, int right) {

		int base = data[left]; // 就是我们的基准数,取序列的第一个,不能用data[0]
		int ll = left; // 表示的是从左边找的位置
		int rr = right; // 表示从右边开始找的位置
		while (ll < rr) {
			// 从后面往前找比基准数小的数
			while (ll < rr && data[rr] >= base) {
				rr--;
			}
			//这里有个小技巧,如果ll < rr为true,说明 data[rr] >= base = false,就找到比基准数小的,就要交换
			if (ll < rr) { // 表示是找到有比之大的
				int temp = data[rr];
				data[rr] = data[ll];
				data[ll] = temp;
				ll++;
			}
			// 从前面往后找比基准数大的数
			while (ll < rr && data[ll] <= base) {
				ll++;
			}
			if (ll < rr) {
				int temp = data[rr];
				data[rr] = data[ll];
				data[ll] = temp;
				rr--;
			}
		}
		// 肯定是递归 分成了三部分,左右继续快排,注意要加条件不然递归就栈溢出了
		//ll:循环终止时为基准数在最中间,然后将ll左右两部分继续递归
		if (left < ll)
			qSort(data, left, ll - 1);
		if (ll < right)
			qSort(data, ll + 1, right);

	}
}

        다양한 정렬 비교:

수많은 정렬 알고리즘 중에서 어떻게 선택해야 할까요?

1. 시나리오 분석: 안정적인지 불안정한지

2. 데이터 볼륨: 데이터 볼륨이 작은 경우 무엇을 선택해야 합니까? 예를 들어 숫자가 50개라면 먼저 입력하세요. (5000*5000=25000000)

3. 분석 공간: 요약하면 고정된 정렬 알고리즘이 없으며 모든 것을 상황에 따라 분석해야 합니다. 하지만 분석하는 방법을 모른다면 병합이나 빠른 정렬을 선택하세요.

        4: 계산 정렬

        가능한 가장 효율적인 알고리즘을 사용하여 한 지방에서 200만 명의 학생의 대학 입시 점수를 정렬하는 방법(점수는 소수점 이하 2자리만 최대 범위로 0에서 900까지만 갖는다고 가정).

package sorttest;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

/**
 * 如何对一个省200万学生的高考成绩(假设成绩最多只有2位小数,0~900范围)进行排序,用尽可能高效的算法。
 *	计数排序
 */

public class CountSort {
	public static void main(String[] args) throws Exception {
		String str = null;
		String fileName = "D:\\JavaCode\\tulin\\src\\sorttest\\200w.txt";
		InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
		BufferedReader br = new BufferedReader(isr);
		int data[] = new int[2100002];
		int i = 0;
		//遍历所有的数据存到数组中
		while ((str = br.readLine()) != null) {
			double a = Double.valueOf(str);
			a = a * 100;
			data[i++] = (int) a;
			// System.out.println((int) a);
		}
		System.out.println("开始值为" + i);
		long start = System.currentTimeMillis();
		countSort(data, 0, data.length - 1);
		System.out.println("结束时间为" + (System.currentTimeMillis() - start) + "ms");
	}

	public static void countSort(int data[], int min, int max) throws Exception {
		int counts[] = new int[max + 1];
		//将所存的数字按照数组下标存储计数,
		for (int i = 0; i < data.length; i++) {
			counts[data[i]]++;
		}

		File file = new File("D:\\JavaCode\\tulin\\src\\sorttest\\200w-csort.txt");
		Writer out = new FileWriter(file);

		//同时从0开始遍历,所以也默认排好序,直接输出
		for (int i = 0; i <= max; i++) {
			if (counts[i] > 0) {
				for (int j = 0; j < counts[i]; j++) {
					out.write(((double) (i / 100.0)) + "\r\n");
				}
			}
		}
		out.close();
	}
}

추천

출처blog.csdn.net/qq_67801847/article/details/132692649