php企业网站开发实训报告网站发布到ftp
php企业网站开发实训报告,网站发布到ftp,wordpress位置,怎么开发一个直播app排序算法
基础排序
冒泡排序
核心为交换#xff0c;通过不断进行交换#xff0c;将大的元素一点一点往后移#xff0c;每一轮最大的元素排到对应的位置上#xff0c;形成有序。 设数组长度为N#xff0c;过程为:
共进行N轮排序每一轮排序从数组的最左边开始#xff0…排序算法
基础排序
冒泡排序
核心为交换通过不断进行交换将大的元素一点一点往后移每一轮最大的元素排到对应的位置上形成有序。 设数组长度为N过程为:
共进行N轮排序每一轮排序从数组的最左边开始两两元素进行比较左边元素大于右边元素就交换两个元素的位置否则不变。每轮排序都会将剩余元素中最大的一个推到最右边下次排序就不再考虑对应位置的元素。
注意交换不能直接进行需要中间元素。 实际上排序不需要N轮N-1轮即可最后一轮只有一个元素未排序。
// 冒泡排序
void BubbleSort(int arr[], int size)
{for(int i 0; i size-1 ;i) // 减1是不考虑最后一次交换{for(int j 0 ; j size - i - 1; j ){if(arr[j] arr[j1]){int tmp arr[j]; // 加入中间元素tmp进行交换arr[j] arr[j1];arr[j1] tmp;}}}
}int main()
{int size 7;int arr1[] {2,4,1,7,4,9,3};BubbleSort(arr1, size);for(int i 0 ; i size;i){printf(%d , arr1[i]);}
}优化如果整轮排序中没有出现任何交换则说明数组是有序的内层循环中加入标记 没有发生任何交换则flag一定是1数组有序
// 改进没有出现交换则已经有序
void BubbleSort1(int arr[], int size)
{for(int i 0 ; i size - 1; i){_Bool flag 1; // 加入标记for(int j 0 ; j size - 1 - i; j){ int tmp arr[j];arr[j] arr[j1];arr[j1] tmp;}if(flag){break;}}
}排序稳定性大小相同的两个元素在排序前和排序后的先后顺序不变则排序算法就是稳定的。比如以上的冒泡排序法只会在前者大于后者的情况下才会发生交换不会影响到相等的两个元素。
插入排序
类似于斗地主的插牌。默认一开始只有第一张牌是有序的剩余部分进行遍历然后插到前面对应的位置上。 设数组长度为N
一共进行N轮排序每轮排序会从后面依次选择一个元素与前面已经处于有序的元素从后往前比较直到遇到一个不大于当前元素的元素将当前元素插入到此元素的前面。插入元素后后续元素则全部后移一位。当后面所有元素全部遍历完成全部插入到对应位置之后结束排序。
// 插入排序
void InsertSort(int arr[], int size)
{for(int i 1; i size -1; i) // 从第2个元素开始{int tmp arr[i], j i;while (j 0 arr[j-1] tmp) // 只要j0并且前一个元素大于当前元素{arr[j] arr[j-1]; // 交换前一个元素j--;}arr[j] tmp;}
}
int main()
{int arr1[] {2,1,8,5,6,4};InsertSort(arr1, 6);printArray(arr1, 6);
}改进寻找插入位置上逐个比较花费时间长如果前面一部分元素已经是有序状态可以考虑使用二分搜索算法来查找对应的插入位置节省插入点的时间。
// 二分搜索法
int BinarySearch(int arr[], int left, int right, int target)
{int mid;while(left right){mid (left right) / 2;if(target arr[mid]){return mid 1;}else if (target arr[mid]){right mid - 1; // 目标值小于中间的值往左边去找}else{left mid 1; // 往右边去找}}return left; // 二分划分范围left就是插入的位置
}
// 改进的插入排序
void InsertSort1(int arr[], int size)
{for(int i 0 ; i size; i){int tmp arr[i];int j BinarySearch(arr,0,size-1,arr[i]); // 二分搜索查找插入的位置for( int k i ; k j; k--){arr[k] arr[k-1]; // 往后移}arr[j] tmp;}
}算法稳定性在优化前的插入排序实际上是不断向前寻找一个不大于待插入元素的元素相等时只会插入到其后面不会修改相等元素的顺序而改进后的二分搜索法可能会将两个连续相等元素分割开来。
选择排序
每次都去后面找一个最小的放到前面。 设数组长度为N
共进行N轮排序每轮排序会从后面的所有元素中寻找一个最小的元素与已经排序好的下一个位置进行互换进行N轮交换后得到有序数组
// 选择排序
void SelectSort(int arr[], int size)
{for(int i 0 ; i size - 1; i) // N-1轮排序{int min i ; // 记录当前最小的元素默认是剩余元素中的第一个for(int j i 1; j size;j){if(arr[min] arr[j]){min j; }int tmp arr[i]; // 找出最小元素之后开始交换arr[i] arr[min];arr[min] tmp;}}
}
// 打印
void printArray(int arr[],int size)
{for(int i 0 ; i size;i){printf(%d , arr[i]);}
}
int main()
{int arr1[] {2,9,6,8,3,6,5};SelectSort(arr1 , 7);printArray(arr1, 7);
}改进因为每次需要选一个最小的不妨顺便选个最大的小的往左边丢大的往右边丢。
// 交换
void swap(int* a, int*b)
{int tmp *a;*a *b;*b tmp;
}
// 优化的选择排序
void SelectSort1(int arr[], int size)
{int left0, right size - 1; // 假设左右排好序往中间缩小while (left right){int max right, min left;for(int i left; i right; i){// 同时找最大和最小的if(arr[i] arr[min]){min i;}if(arr[i] arr[max]){max i;}}swap(arr[max], arr[right]); // 先把大的换到右边// 大的换到右边之后有可能被换出来的是最小的需要判断以下// 如果遍历完最小的是当前右边排序的第一个元素// 将min换到那个位置if(min right){min max;}swap(arr[min], arr[left]);left;right--;}
}稳定性由于每次寻找的是最小的元素向前插入时会发生交换操作当存在两个连续相等元素破坏了原有的顺序。不稳定的。
比较三种基础排序
冒泡排序优化后
最好情况时间复杂度O(n)本身是有序的只需要一次遍历。最坏情况时间复杂度O(n^2)倒序。空间复杂度O(1)只需要一个变量存储需要交换的变量稳定 插入排序最好情况时间复杂度O(n)本身是有序的插入的位置也是同样的位置不变动任何元素最坏情况时间复杂度O(n^2)倒序。空间复杂度O(1)只需要一个变量存储抽出来的元素稳定 选择排序最好情况时间复杂度O(n^2)即使数组本身是有序的每一轮还得将剩余部分依次找完才确定最小的元素最坏情况时间复杂度O(n^2)空间复杂度每一轮需要记录最小元素位置空间复杂度为O(1)不稳定
进阶排序
快速排序
快速排序是冒泡排序的进阶版由于冒泡排序是对相邻元素进行比较和交换每次只能移动一个位置效率相对较低而快速排序是从两端向中间进行一轮就可将较小的元素交换到左边较大的元素交换到右边。
实际上每一轮目的就是将较大的丢到基准右边较小的丢到基准左边
一开始排序为整个数组排序之前以第一个元素作为基准从最右边向左看依次将每一个元素与基准元素进行比较如果该元素比基准元素小就与左边遍历位置上的元素一开始为基准元素位置进行交换保留右边当前遍历的位置交换后转为从左边往右开始遍历元素如果发现比基准元素大则与之前保留右边遍历的位置上元素进行交换同样保留左边当前遍历的位置当左右遍历撞到一起本轮快速排序完成中间的位置元素就是基准元素以基准位置为中心划分左右两边同样方式进行
代码实现
// 快速排序
void QuickSort(int arr[], int start, int end)
{if(start end) // 不满足初始位置则返回{return;}int left start, right end; // 定义两个指向左右两个端点的指针int pivot arr[left]; // 预先确定基准点为左端第一个元素while (left right){while(left right arr[right] pivot){right--;// 从右往左看}arr[left] arr[right]; // 比基准值小就放到左边去while (left right arr[left] pivot){left; // 从左往右看}arr[right] arr[left]; // 比基准值大就放到右边arr[left] pivot; //相遇位置即为基准存放的位置}QuickSort(arr, start , left-1); //划分基准左边QuickSort(arr, left1, end); // 划分基准右边 再次进行快速排序
}测试
int main()
{int arr1[] {9,3,6,3,4,8,1,2};QuickSort(arr1, 0 , 8);for(int i 0; i 8 ; i){printf(%d , arr1[i]);}
}双轴快速排序
快速排序的升级版双轴快速排序可对大数组进行。如果遇到数组完全倒序的情况 每一轮需要完整遍历整个范围每一轮最大或最小的元素被推向两边则此完全倒序情况快速排序退化为冒泡排序。为解决这种极端情况再添加一个基准元素使得数组可分为三段。 分为三段后每轮双轴排序结束后对三段继续进行双轴快速排序。该适用于那些量比较大的数组。
首先取出首元素和尾元素作为两个基准对其进行比较若基准1大于基准2先交换两个基准。 需要创建三个指针 从橙色指针所指元素开始进行判断
小于基准1那需要先将蓝色指针向后移把元素交换到蓝色指针那去然后橙色指针也向后移动不小于基准1且不大于基准2直接把橙色指针向前移动即可大于基准2需要丢到右边去先将右边指针左移不断向前找到一个比基准2小的进行交换 橙色指针与绿色指针之间即为待排序区域 代码实现
void swap(int* a, int*b)
{int tmp *a;*a *b;*b tmp;
}void dualPivotQuickSort(int arr[], int start, int end)
{if(start end){return; // 结束条件}if(arr[start] arr[end]) // 首尾两个基准比较{swap(arr[start], arr[end]); // 大的换到后面}int pivot1 arr[start], pivot2 arr[end]; // 取出两个基准元素int left start, right end, mid left 1; // 分三个区域三个指针while (mid right){if(arr[mid] pivot1) // mid所指向元素小于基准1需要放到最左边{swap(arr[left], arr[mid]); // 和最左边交换left 和 mid向前移动}else if(arr[mid] pivot2) // 不小于基准1但小于基准2在中间{mid; // 本身在中间向前移动以缩小范围}else // 右边的情况{while (arr[--right] pivot2 right mid); // 先移动右边指针需要右边位置来存放需要换过来的元素if(mid right){break; // 剩余元素找完没有比基准2小的可直接结束}swap(arr[mid], arr[right]); // 还有剩余元素找到比基准2小的直接交换 }} swap(arr[left], arr[start]); // 基准1与left交换基准1左边元素都比其小swap(arr[right],arr[end]); // 基准2与right交换基准2右边元素都比其大// 继续对剩下三个区域双轴快速排序dualPivotQuickSort(arr, start,left-1);dualPivotQuickSort(arr, left1, right-1);dualPivotQuickSort(arr, right1, end);
}dualPivotQuickSort(arr1, 0, 8);for(int i 0; i 8 ; i){printf(%d , arr1[i]);}希尔排序缩小增量排序
直接插入排序的进阶版极端情况会出现让所有已排序元素后移的情况比如刚好要插入的是一个特别小的元素为解决这种问题对整个数组按照步长进行分组优先比较距离较远的元素。
步长是由一个增量序列当增量序列一般使用 n 2 、 n 4 、 n 8 . . . 、 1 \frac{n}{2}、\frac{n}{4}、\frac{n}{8}...、1 2n、4n、8n...、1这样的序列。 设数组长度为N详细过程为:
求出最初步长,n/2整个数组按照步长进行分组两两一组n为奇数第一组有三个元素分别在分组内插入排序排序后将步长/2重新分组重复上述步骤直到步长为1插入排序最后一遍结束 插入排序后小的元素尽可能地向前走缩小步长4/22 代码实现
// 希尔排序
void shellSort(int arr[], int size)
{int delta size / 2;while (delta 1) // 使用之前的插入排序此时需要考虑分组{for(int i delta; i size; i) // 从delta开始前delta个组的第一个元素默认是有序状态{int j i, tmp arr[i]; // 依然是把待插入的先抽出来while (j delta arr[j - delta] tmp) {// 需要按步长往回走所以是j-deltaj必须大于等于delta才可以,j-delta小于0说明前面没有元素arr[j] arr[j - delta];j - delta;}arr[j] tmp;}delta / 2; // 分组插排结束之后再计算步长}
}
int main()
{int arr[] {3,5,7,2,9,0,6,1,8,4};shellSort(arr, 10);for(int i 0 ; i 10; i){printf(%d , arr[i]);}
}尽管有循环多次但时间复杂度比O(n^2)小小的元素往左靠。希尔排序不稳定因为按步长分组有可能相邻得两个相同元素后者在自己组内被换到前面去。
堆排序
选择排序一种但能比选择排序更快。 小根堆小顶堆对一棵不完全二叉树树中父亲结点都比孩子结点小大根堆大顶堆树中父亲结点都比孩子节点大。 堆是一棵完全二叉树数组来表示 构建一个堆将一个无序的数组依次输入最后存放的序列是一个按顺序排放的序列。
但仍需要额外O(n)的空间作为堆可以对其进一步优化减少空间上的占用。直接对给定的数组进行堆的构建 设数组长度为N
将给定数组调整为大顶堆进行N轮选择每次选择大顶堆顶端元素从数组末尾开始向前存放交换堆顶和堆的最后一个元素交换完成后重新对堆的根节点进行调整使其继续满足大顶堆的性质当N轮结束后得到从小到大的数组
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/92301.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!