一、十大排序算法
算法分类
1.比较类排序:通过比较元素大小,决定元素次序的排序。
PS:时间复杂度无法突破O(nlongn),因此也被称为非线性时间排序。
2.非比较类排序:不通过比较元素大小,也可以决定元素次序的排序。
PS:以线性时间运行,因此也被称为线性时间排序。
算法复杂度分析
1.冒泡排序(Bubble Sort)
从一个元素开始到最后一个元素结束,比较相邻的两个元素大小。如果前一个比后一个大,就交换它们的位置;如果前一个比后一个小,就不交换。每一轮都从第一个元素开始到上一轮最后一个元素的前一个元素结束。
代码如下(示例):
public class BubbleSort {
public static void main(String[] args) {
int[] array = {2,3,4,5,6,1,6,3,4,0,1,5};
int[] ints = bubbleSort(array);
System.out.println(Arrays.toString(ints));
}
private static int[] bubbleSort(int[] array){
int len = array.length;
for(int i = 0; i < len; i ++){
for(int j = 0; j < len -1-i; j ++){
if(array[j] > array[j+1]){
int temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
return array;
}
}
2.选择排序(Selection Sort)
从第一个元素开始到最后一个元素结束,比较所有元素的大小。取出最小的元素放在第一个元素的位置。每一轮都从上一轮第一个元素的下一个元素开始到最后一个元素结束。
代码如下(示例):
public class SelectSort {
public static void main(String[] args) {
int[] nums = {2,1,3,7,4,5,6,6,4,0,3,9,10,0};
selectSort(nums);
System.out.println(Arrays.toString(nums));
}
private static int[] selectSort(int[] array){
for (int i = 0; i < array.length; i++) {
int index = i;
int temp;
for(int j = i; j < array.length; j ++){
if(array[index] > array[j]){
index = j;
}
}
//先存最小值
temp = array[index];
//最小值位置上变成i位置上的数值
array[index] = array[i];
//再将最小值放在i位置
array[i] = temp;
}
return array;
}
3.插入排序(Insertion Sort)
排序区间分为两部分,前半部分是有序区间,后半部分是无序区间。开始时有序区间只有第一个元素,取无序区间第一个元素,并在有序区间从后向前扫描。如果该元素大于有序区间中的元素,就放在这个元素后面;如果该元素小于有序区间中的元素,就继续向前扫描比较,直到放到有序位置。然后有序区间+1,无序区间-1。再取出无序区间第一个元素,重复以上步骤。
代码如下(示例):
public class InsertSort {
public static void main(String[] args) {
int[] array = {2,1,3,7,4,5,6,6,4,0,3,9,10,0};
insertSort(array);
System.out.println(Arrays.toString(array));
}
private static void insertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
//待插入的数据
int key = array[i];
//已排序的数组长度
int j = i - 1;
//如果j>0 且 待排序的数据小于已排序中的数据
while (j >= 0 && key < array[j]){
//则已排序的中大于待排序的元素下标+1,往后面移位
array[j + 1] = array[j];
j --;
}
//把待排序的数据插入已排序的部分中
array[j+1] = key;
}
}
}
4.希尔排序(Shell Sort)
希尔排序是插入排序的改进版本,突破了插入排序的O(n²)。它与插入排序的不同之处在于,它会优先比较距离远的元素。因此希尔排序又叫缩小增量排序。
希尔排序将要排序的序列按照步长gap进行分组,先在这几组内进行插入排序,之后在调整步长gap得到分组内进行插入排序,最后整体进行一次插入排序。这样可以让一个元素朝最终位置大走一步,然后再缩小步长,使元素更靠近最终位置。最后一次插入排序时,整个序列几乎已经排好序了。
代码如下(示例):
public class ShellSort {
public static void main(String[] args) {
int[] nums = {2,1,3,7,4,5,6,6,4,0,3,9,10,0};
shellSort(nums);
System.out.println(Arrays.toString(nums));
}
private static void shellSort(int[] array) {
int gap = array.length / 2;
while (gap>0) {
for (int i = gap; i < array.length; i++) {
//
int left = i - gap;
int right = array[i];
while (left >= 0 && array[left] > right) {
int temp = array[left];
array[left] = array[left + gap];
array[left + gap] = temp;
left = left - gap;
}
}
gap = gap/2;
}
}
5.快速排序(Quick Sort)
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
从数列中挑出一个元素(通常选第一个元素),称为 “基准”(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
对左右两个分区重复以上步骤直到所有元素都是有序的;
代码如下(示例):
public static void main(String[] args) {
int[] nums = {2,1,3,7,4,5,6,6,4,0,3,9,10,0,-1};
quickSort(nums);
System.out.println(Arrays.toString(nums));
}
private static void quickSort(int[] nums){
fastSwap(nums,0,nums.length-1);
}
private static void fastSwap(int[] nums, int left, int right){
if(left < right){
int swap = swap(nums, left, right);
fastSwap(nums,left,swap-1);
fastSwap(nums,swap+1,right);
}
}
private static int swap(int[] array,int left, int right){
//基准数据,一般选择最左侧数值
int temp = array[left];
//当左 < 右时
while (left < right) {
//先从右侧元素比较,如果右侧元素小于基准值,将右侧数据放到左侧left位置
while (left < right && array[right] >= temp) {
right--;
}
if (left < right) {
array[left] = array[right];
}
//当右侧出现一个一个小于基准值的数据之后,开始从左侧与基准值比较,当出现大于基准值得数据时,将数据放到右侧right位置
while (left < right && array[left] <= temp) {
left++;
}
if (left < right) {
array[right] = array[left];
}
//如果左右位置相等时,则将基准值放到该位置
if (left == right) {
array[left] = temp;
}
}
return left;
}
}
6.归并排序(Merge Sort)
归并排序(Merge Sort)是一种基于分治思想的排序算法。它将待排序的数组分成两个长度相等的子数组,然后对这两个子数组分别进行归并排序,最后将两个排好序的子数组合并成一个有序的数组。
算法描述
- 如果待排序列只有一个元素,则直接返回,否则将长度为n的待排序列分成两个长度为n/2的子序2列,递归进行调用进行分割知道每个子序列中只有一个元素;
- 此时的每个子序列被认为是有序的,然后递归调用的返回子序列进行两两合并;
- 合并过程中完成排序操作,具体操作为设定两个指针,分别指向两个已经排序子序列的起始位置;
- 比较两个指针所指向的元素,选择相对小的元素放入到合并返回的数组,并移动指针到下一位置;
- 重复步骤3~4直到某一指针达到序列尾;
- 将另一序列剩下的所有元素直接复制到合并序列尾,最终得到的新序列就是有序序列。
代码如下(示例):
public static void main(String[] args) {
int[] nums = {2,1,3,7,4,5,6,6,4,0,3,9,10,0};
int[] temp = new int[nums.length];
mergerSort(nums,0,nums.length-1,temp);
System.out.println(Arrays.toString(temp));
}
public static void mergerSort(int[] nums,int left, int right,int[] temp){
if(left < right){
int mid = (left + right) / 2;
//向左递归进行分解
mergerSort(nums, left,mid,temp);
//向右递归进行分解
mergerSort(nums,mid+1,right,temp);
//合并
merge(nums,temp,left,mid,right);
}
}
/** 合并的方法
* @param nums 原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 临时数组
*/
public static void merge(int[] nums, int[] temp, int left, int mid, int right){
//初始化i,左边的初始索引
int i = left;
//初始化j,右边的初始化索引
int j = mid + 1;
//指向temp数据的当前索引
int t = 0;
//1、先把左右两边的数据进行比较,从小到大放到temp数组中
while(i <= mid && j <= right){
if(nums[i] <= nums[j]){
temp[t] = nums[i];
t = t+1;
i = i+1;
}else {
temp[t] = nums[j];
j = j+1;
t = t+1;
}
}
//2、把左边剩余元素填充到temp中
while (i <= mid){
temp[t] = nums[i];
i = i + 1;
t = t + 1;
}
//3、把右边剩余元素填充到temp中
while (j <= right){
temp[t] = nums[j];
t = t + 1;
j = j + 1;
}
//4、将temp中的数据拷贝到nums中
//注意:不是每次都拷贝所有,只有最后一次才拷贝所有
t = 0;
int tempLeft = left;
while (tempLeft <= right){
nums[tempLeft] = temp[t];
t = t + 1;
tempLeft = tempLeft + 1;
}
}
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。