首页 > 编程语言 >408 数据结构排序算法

408 数据结构排序算法

时间:2024-07-28 20:19:07浏览次数:15  
标签:arr 排序 nums int void while && 数据结构 408

第六章 排序

6.1冒泡排序

void swap(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

//外层循环是说明n个元素排好序需要经过n-1轮
	for (int i = n - 1; i > 0; i--) {
		bool flag = true;
		for (int j = 0; j < i; j++) {
			if (arr[j] > arr[j + 1]) {
				flag = false;
				swap(arr, j, j + 1);
			}
		}
		if (flag == true) {
			break;
		}
	}
	/*for (int i = 0; i < n - 1; i++) {
		for (int j = n - 1; j > i; j--) {
			if (arr[j] > arr[j - 1]) {
				swap(arr, j, j - 1);
			}
		}
	}*/
//递归写法
void bubbleSort2(int arr[], int n) {
	if (n == 1) {
		return;
	}
	for (int i = 0; i < n-1; i++) {
		if (arr[i] > arr[i + 1]) {
			swap(arr, i, i + 1);
		}
	}
	bubbleSort2(arr, --n);
}

void printArray(int arr[], int n) {
	for (int i = 0; i < n; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

6.2选择排序

//简单选择排序
void selectSort(int arr[], int n) {
	for (int i = 0; i < n - 1; i++) {
		int min = arr[i];
		int minIndex = i;
		for (int j = i + 1; j < n; j++) {
			if (arr[j] < min) {
				min = arr[j];
				minIndex = j;
			}
		}
		if (minIndex != i) {
			swap(arr, i, minIndex);
		}
	}
}

6.3直接插入排序

//插入排序
void insertSort(int arr[], int n) {
	for (int i = 0; i < n - 1; i++) {
		for (int j = i + 1; j > 0 && arr[j] > arr[j - 1]; j--) {
			swap(arr, j, j - 1);
		}
	}
}

6.4折半插入排序

int insertIndex(int arr[],int target, int n) {
	int low = 0, high = n - 1;
	while (low <= high) {
		int mid = (low + high) / 2;
		if (arr[mid] <=  target) {
			low = mid + 1;
		}
		else {
			high = mid - 1;
		}
	}
	return low;
}
//折半插入排序
void binaryInsertSort(int arr[], int n) {
	for (int i = 1; i < n; i++) {
		int index = insertIndex(arr, arr[i], i);
		for (int j = i; j > index; j--) {
			swap(arr, j, j - 1);
		}
	}
}

6.5希尔排序

//希尔排序
void shellSort(int arr[], int n) {
	for (int gap = n / 2; gap >= 1; gap /= 2) {
		for (int i = gap; i < n; i++) {
			for (int j = i; j >= gap && arr[j] < arr[j - gap]; j -= gap) {
				swap(arr, j, j - gap);
			}
		}
	}
    
}

//希尔排序
void shellSort(int arr[], int n) {
	for (int gap = n / 2; gap >= 1; gap /= 2) {
		for (int i = 0; i < n - gap; i++) {
			for (int j = i + gap; j >= gap && arr[j] < arr[j - gap]; j -= gap) {
				swap(arr, j, j - gap);
			}
		}
	}
}

6.6快速排序

6.6.1双边快排,以第一个元素为枢轴元素

void swap(int arr[], int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
int partition(int arr[], int L, int R) {
	int p = arr[L];
	int i = L;
	int j = R;
	while (i < j) {
		while (i < j && arr[j] >= p) {
			j--;
		}
		while (i< j&& arr[i] <= p) {
			i++;
		}
		swap(arr, i, j);
	}
	swap(arr, L, i);
	return i;
}

void quick(int arr[], int L, int R) {
	if (L >= R) {
		return;
	}
	int pos = partition(arr, L, R);
	quick(arr, L, pos - 1);
	quick(arr, pos+1, R);
}
void quickSort(int arr[], int n) {
	if (n < 2) {
		return;
	}
	quick(arr, 0, n - 1);
}

6.6.2双边快排,以最后一个元素为枢轴元素

void swap(int arr[], int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
//双边快排(以最后一个元素为枢轴)
int partition3(int arr[], int L, int R) {
    int p = arr[R];
    int i = L;
    int j = R;
    while (i < j) {
        while (i < j && arr[i] <= p) {
            i++;
        }
        while (i < j && arr[j] >= p) {
            j--;
        }
        swap(arr, i, j);
    }
    swap(arr, R, i);
    return i;
}

void quick3(int arr[], int L, int R) {
	if (L >= R) {
		return;
	}
	int pos = partition3(arr, L, R);
	quick3(arr, L, pos - 1);
	quick3(arr, pos + 1, R);
}
void quickSort3(int arr[], int n) {
	if (n < 2) {
		return;
	}
	quick3(arr, 0, n - 1);
}

6.6.3双边快排,随机生成种子

//双边快排(以最后一个元素为枢轴)

void swap(int arr[], int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
// 生成随机索引
int randomIndex(int L, int R) {
    return rand() % (R - L + 1) + L;
}

int partition4(int arr[], int L, int R) {
    int randIdx = randomIndex(L, R);
    int p = arr[randIdx];
    // 将随机选择的元素移动到最后一个位置
    int temp = arr[randIdx];
    arr[randIdx] = arr[L];
    arr[L] = temp;

    int i = L;
    int j = R;
    while (i < j) {
        while (i < j && arr[j] >= p) {
            j--;
        }
        while (i < j && arr[i] <= p) {
            i++;
        }
        swap(arr, i, j);
    }
    swap(arr, L, i);
    return i;
}

void quick4(int arr[], int L, int R) {
    if (L >= R) {
        return;
    }
    int pos = partition4(arr, L, R);
    quick4(arr, L, pos - 1);
    quick4(arr, pos + 1, R);
}

void quickSort4(int arr[], int n) {
    if (n < 2) {
        return;
    }
    srand(time(NULL)); // 设置随机种子
    quick4(arr, 0, n - 1);
}

6.7归并排序

int* newarr = NULL;
void merge(int arr[], int left, int mid, int right) {
	for (int i = left; i <= right; i++) {
		newarr[i] = arr[i];
	}
	int i = left;
	int j = mid + 1;
	int k = left;
	while (i <= mid && j <= right) {
		if (newarr[i] <= newarr[j]) {
			arr[k++] = newarr[i++];
		}
		else {
			arr[k++] = newarr[j++];
		}
	}
	while (i <= mid) {
		arr[k++] = newarr[i++];
	}
	while (j <= right) {
		arr[k++] = newarr[j++];
	}
}

void sort(int arr[], int left, int right) {
	if (left >= right) {
		return;
	}
	int mid = (left + right) / 2;
	sort(arr, left, mid);
	sort(arr, mid + 1, right);
	merge(arr, left, mid, right);
}

//归并排序(函数入口)
void mergeSort(int arr[], int n) {
	if (n < 2) {
		return;
	}
	newarr = (int*)malloc(sizeof(int) * n);
	sort(arr, 0, n - 1);
}

6.8堆排序

//从下标为k的元素开始下潜
void down(int arr[], int k, int n) {
	int left = k * 2 + 1;
	int right = left + 1;
	int max = k;
	if (left < n && arr[left] > arr[max]) {
		max = left;
	}
	if (right < n && arr[right] > arr[max]) {
		max = right;
	}
	if (max != k) {
		swap(arr,max, k);
		down(arr,max,n);
	}
}
//建堆
void heapify(int arr[], int n) {
	for (int i = n / 2; i >= 0; i--) {
		down(arr, i, n);
	}
}

//堆排序
void heapSort(int arr[], int n) {
	heapify(arr, n);
	for (int i = n-1; i > 0; i--) {
		swap(arr, i, 0);
		down(arr, 0, i);
	}
}

6.9刷题

1.以arr数组中第ki的元素作为分隔,使左边的元素值都比ki所对应的元素值小,右侧都比其大。

void change(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
//以arr数组中第ki的元素作为分隔,
//使左边的元素值都比ki所对应的元素值小,右侧都比其大
void quickPart(int arr[], int Ki, int n) {
	//第ki个,所以先对ki合法性做个判断
	if (Ki < 1 || Ki > n) {
		return;
	}
	change(arr, 0, Ki - 1);	//先将第ki个元素第一个交换,后面代码就可以直接用讲的了
	int p = arr[0];
	int i = 0;
	int j = n - 1;
	while (i < j) {
		while (i < j && arr[j] >= p) {
			j--;
		}
		while (i < j && arr[i] <= p) {
			i++;
		}
		change(arr, i, j);
	}
	change(arr, 0, i);
}

1.已知线性表按顺序存储,且每个元素都是不相同的整数型元素,设计把所有奇数移动到
所有偶数前边的算法( 要求时间最短,辅助空间最小)。

void change(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
void oddFrontEvenLast(int arr[],int n) {
	int low = 0, high = n - 1;
	while (low < high) {
		//找第一个偶数
		while (low < high && arr[low] % 2 == 1) {
			low++;
		}
		//找第一个奇数
		while (low < high && arr[high] % 2 == 0) {
			high--;
		}
		change(arr, low, high);
		low++;
		high--;
	}
}

02.试编写一个算法,使之能够在数组L[1...n]中找出第k小的元素( 即从小到大排序后处
于第k个位置的元素)。

/*思路1:用小根堆找到K个,建立小根堆时间复杂度O(n),k个下沉操作,时间复杂度O(klogn),整体(n+klogn)*/
//从下标为k的元素开始下潜
void down(int arr[], int k, int n) {
	int left = k * 2 + 1;
	int right = left + 1;
	int min = k;
	if (left < n && arr[left] < arr[min]) {
		min = left;
	}
	if (right < n && arr[right] < arr[min]) {
		min = right;
	}
	if (min != k) {
		change(arr, min, k);
		down(arr, min, n);
	}

}
//建小顶堆
void heapify(int arr[], int n) {
	for (int i = n / 2 - 1; i >= 0; i--) {
		down(arr, i, n);
	}
}
/*
02.试编写一个算法,使之能够在数组L[1...n]中找出第k小的元素( 即从小到大排序后处
于第k个位置的元素)。
*/
int getKMin(int arr[], int k, int n) {
	if (k < 1 || k > n) {
		return -999;	//出错
	}
	//先建立小顶堆
	heapify(arr, n);
	// 依次移除堆顶元素,直到第k小的元素
	for (int i = 0; i < k - 1; i++) {
		change(arr, 0, n - 1 - i);
		down(arr, 0, n - i - 1);
	}
	// 第k小的元素即为当前堆顶元素
	return arr[0];
}
/*思路2:利用快排思想,平均时间复杂度可达到O(n)*/
//L和R分别代表的是左右边界
int partition1(int arr[], int L, int R) {
	int p = arr[L];
	int i = L;
	int j = R;
	while (i < j) {
		while (i < j && arr[j] >= p) {
			j--;
		}
		while (i < j && arr[i] <= p) {
			i++;
		}
		change(arr, i, j);
	}
	change(arr, L, i);
	return i;
}


int quickPartition(int arr[], int k, int L,int R) {
	int p = partition1(arr, L, R);
	int rank = p - L + 1; // 计算当前划分后 pivot 的排名
	if (rank == k) {
		return arr[p]; // 找到第k小的元素
	}
	else if (k < rank) {
		return quickPartition(arr, k, L, p - 1); // 在左侧继续查找
	}
	else {
		return quickPartition(arr, k - rank, p + 1, R); // 在右侧继续查找
	}
}

int getKMin2(int arr[], int k, int n) {
	if (k < 1 || k > n) {
		return -1;
	}
	return quickPartition(arr, k, 0, n - 1);
}

3.荷兰国旗问题:设有一个仅由红、白、蓝三种颜色的条块组成的条块序列,存储在
一个顺序表中,请编写一个时间复杂度为O(n)的算法,使得这些条块按红、白、蓝
的顺序排好,即排成荷兰国旗图案。请完成算法实现:

typedef enum { RED=0, WHITE=1, BLUE=2 } color;
void swap2(color a[], int i, int j) {
	color temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
void Flag_Arrange(color a[], int n) {
	int redPart = -1;
	int bluePart = n;
	int i = 0;
	while (i < bluePart) {
		if (a[i] == RED) {
			swap2(a, i++, ++redPart);
		}
		else if (a[i] == BLUE) {
			swap2(a, i, --bluePart);
		}
		else {
			i++;
		}
	}
}

4.给定一个包含 [0, n]n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。
int missingNumber(int nums[], int n) {
	int ans = 0;
	for (int i = 0; i <= n; i++) {
		if (i == n) {
			ans ^= i;
		}
		else {
			ans ^= (i ^ nums[i]);
		}
	}
	return ans;
}

5.给定一个非负整数数组 numsnums 中一半整数是 奇数 ,一半整数是 偶数 。对数组进行排序,以便当 nums[i] 为奇数时,i 也是 奇数 ;当 nums[i] 为偶数时, i 也是 偶数

示例 1:

输入:nums = [4,2,5,7]
输出:[4,5,2,7]
解释:[4,7,2,5],[2,5,4,7],[2,7,4,5] 也会被接受。

示例 2:

输入:nums = [2,3]
输出:[2,3]
void change(int arr[], int i, int j) {
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
void sortArrayByParityII(int nums[],int n) {
	int high = n;
	int low = 1;
	for (int i = 0; i < high; i += 2) {
		if ((nums[i] & 1) == 1) {
			while (nums[low] % 2 == 1) {
				low += 2;
			}
			change(nums, i, low);
		}
	}
}

标签:arr,排序,nums,int,void,while,&&,数据结构,408
From: https://www.cnblogs.com/lingchuanfeng/p/18328813

相关文章

  • 408 数据结构查找算法
    第7章查找7.1二分查找需求:在有序数组arr中,查找值为target的元素。若找到返回索引下标,否则返回-1算法思路:找中间值,1.如果target<中间值,在左半区间继续查找,即让high=mid-1​ 2.如果中间值<target,在右半区间继续查找,即让low=mid+1​ 3.直到当lo......
  • 408 数据结构栈算法
    第二章栈2.1顺序栈顺序栈的基本操作#defineMAXSIZE128typedefintElemType;typedefstruct{ ElemTypedata[MAXSIZE]; //用数组实现对栈中元素的存取 inttop; //栈顶指针 intlength; //栈的长度}SqStack;//初始化栈voidinitStack(SqStack&S);//判......
  • 408 数据结构队列算法
    第三章队列3.1顺序队列#defineMAXSIZE64typedefintElemType;typedefstruct{ ElemTypedata[MAXSIZE]; intfront; //队头指针 intrear; //队尾指针 intsize; //队列大小}SeQueue;//初始化队列voidinitQueue(SeQueue&Q){ //对数据元素进行初始化,防止出现......
  • 算法-排序算法
    一、算法和算法分析什么是算法:​ 对特定问题的求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作。算法的五个重要特性:有穷性确定性可行性输入输出算法设计的要求:正确性可读性健壮性高效率与低存储算法效率的度量:​ 算法的执行时间需要依......
  • CSP-S提高组数据结构算法模板大合集
    CSP-S算法总结2.2.1基础知识与编程环境无2.2.2C++程序设计2set/nultisetmap/multimapdeque/priority_queueSTL2.2.3数据结构P1886 滑动窗口/【模板】单调队列#include<iostream>usingnamespacestd;intn,k,a[1000005];intq[1000005],h,t;......
  • 数据结构-二叉树、堆、图
    一、线索二叉树规律:在有n个节点的链式二叉树中必定存在n+1个空指针链式二叉树中有很多的空指针,可以让这些空指针指向前一个节点\后一个节点,从而在有序遍历(中序遍历)二叉树时,不需要使用递归而通过循环即可以完成,并且效率要比递归快得多一定是搜索二叉树线索二叉树的结构typ......
  • C++ 数据结构体解析
    文章目录1.定义结构体2. 访问结构成员3. 结构作为函数参数4. 指向结构的指针5. typedef关键字1.定义结构体C/C++数组允许定义可存储相同类型数据项的变量,但是结构是C++中另一种用户自定义的可用的数据类型,它允许存储不同类型的数据项。结构用于表示一条记......
  • 从零开始学数据结构系列之第四章《克鲁斯卡尔算法应用场景-公交站问题》
    文章目录往期回顾某城市新增7个站点(A,B,C,D,E,F,G),现在需要修路把7个站点连通各个站点的距离用边线表示(权),比如A–B距离12公里问:如何修路保证各个站点都能连通,并且总的修建公路总里程最短?以上图为例,来对克鲁斯卡尔进行演示(假设用数组R保存......
  • Chapter 6: 排序
        在计算机科学中,排序算法是基础且核心的部分,它们被广泛应用于各种领域,如数据处理、信息检索等。C语言作为一种通用的、过程式的计算机程序设计语言,它的运行效率和灵活性使得它成为学习和实现这些排序算法的理想选择。本篇博客将深入探讨一些常见的排序算法,包括冒泡......
  • 数据结构基础的学习
    数据结构:相互之间存在一种或多种特定关系的数据元素的集合。逻辑结构:集合:所有数据在同一个集合中,关系平等。线性:数据和数据之间是一对一的关系树:一对多图:多对多物理结构(在内存当中的存储关系):顺序存储:数据存放在连续的存储单位中。逻辑关系和物理关系一致链式,数据存......