0
点赞
收藏
分享

微信扫一扫

JAVA学习日记十一(数据结构与集合源码)

Java旺 03-23 17:00 阅读 2

1.1、冒泡排序

原理

从数组中(从下标较小的元素开始),依次对相邻两个元素的值进行两两比较,若发现复合交换规则就进行交换,使对应的元素逐渐从前移向后部,就如果水底下的气泡一样逐渐向上冒

排序规则

  • 一共进行数组长度-1次循环

  • 每一趟排序的次数在减少(减去已经排好的数据)并且每一趟比较的次数最长为数组长度-1次

实现思路:定义嵌套循环,外层循环控制循环的次数(趟数),内层循环控制每一趟的比较次数,每一趟比较都会确定一个数,所以每一趟的比较次数都会减少一次

// 一共进行数组长度-1次循环
for(int i = 0; i < 数组长度-1; i++){
  // 每一趟的循环
  for(int j = 0; j < 数组长度-1-i; j++){
    交换数据代码实现逻辑
  }
}

优化

  • 在某趟排序中没有数据的交换,也就是数据没有发生变动,就可以提前结束

实现思路:定义一个变量进行表示,如果发生数据的交换,就更改变量的值,最后判断这个变量是否发生改变从而提前结束循环

// 一共进行数组长度-1次循环
for(int i = 0; i < 数组长度-1; i++){
  // 每一趟的循环
  for(int j = 0; j < 数组长度-1-i; j++){
    交换数据代码实现逻辑
  }
  这里进行判断变量的值,如果没有发生变化就退出循环
}

1.2、选择排序

原理

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

排序规则

  • 一共进行数组长度-1轮排序

  • 每一轮排序的次数都在减少(减去已经排好的数据)并且每一轮比较的次数最长为数组长度-1次

实现思路:先假定当前的这个数为最小数(或最大数)然后和后面的每一个数进行比较,如果发现比当前数更小(更大)的数,就重新确定最小的数,直到遍历到数组最后,获取到本轮最小数,在进行交换

for(int i = 0; i < 数组长度-1; i++){
  定义最小值 = 数组名[i];
  for(int j = i+1; j < 数组长度; j++){
    if(min > 数组名[j]){
      交换得到最小数
    }
  }
  if(最小数 != 数组名[i]){
    排序交换数据
  }
}

例如:

#include <iostream>
using namespace std;
int main() {
    // 定义一个数组
    int arr[] = {12,3,1,5};
    // 外层循环控制轮数
    for(int i = 0; i < sizeof(arr)/ sizeof(int) - 1; i++){
        // 设置最小值为第一个数
        int min = arr[i];
        // 内层循环控制每一轮对比次数--找出每一轮中的最小数
        for(int j = i+1; j < sizeof(arr)/ sizeof(int) ; j++){
            if(min < arr[j]){
                swap(min,arr[j]);
            }
        }
        // 将最小数放到最前面
        if(min != arr[i]){
            swap(min ,arr[i]);
        }
    }
    // 遍历
    for (int a:arr) {
        cout << a;
    }
    return 0;
}

1.3、插入排序

也是一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的、记录数量增1的有序表

原理

插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

排序规则

  • ① 从第一个元素开始,该元素可以认为已经被排序

  • ② 取出下一个元素,在已经排序的元素序列中从后向前扫描

  • ③如果该元素(已排序)大于新元素,将该元素移到下一位置

  • ④ 重复步骤③,直到找到已排序的元素小于或者等于新元素的位置

  • ⑤将新元素插入到该位置后

  • ⑥ 重复步骤②~⑤

例如:

// 插入排序
void InsertSort(int arr[], int len){
    // 检查数据合法性
    if(arr == NULL || len <= 0){
        return;
    }
    for(int i = 1; i < len; i++){
        int tmp = arr[i];
        int j;
        for(j = i-1; j >= 0; j--){
            //如果比tmp大把值往后移动一位
            if(arr[j] > tmp){
               arr[j+1] = arr[j];
            }
            else{
               break;
            }
        }
        arr[j+1] = tmp;
    }
}

优化

直接插入排序每次往前插入时,是按顺序依次往前查找,数据量较大时,必然比较耗时,效率低。

改进思路: 在往前找合适的插入位置时采用二分查找的方式,即折半插入。

改进代码:

// 插入排序改进:二分插入排序
void BinaryInsertSort(int arr[], int len)   
{   
    int key, left, right, middle;   
    for (int i=1; i<len; i++)   
    {   
        key = a[i];   
        left = 0;   
        right = i-1;   
        while (left<=right)   
        {   
            middle = (left+right)/2;   
            if (a[middle]>key)   
                right = middle-1;   
            else   
                left = middle+1;   
        }   

        for(int j=i-1; j>=left; j--)   
        {   
            a[j+1] = a[j];   
        }   
        a[left] = key;          
    }   
}

1.4、快速排序

快速排序算法是对冒泡排序算法的一种改进算法,在当前所有内部排序算法中,快速排序算法被认为是最好的排序算法之一。

思想

通过一趟排序将待排序的序列分割为左右两个子序列,左边的子序列中所有数据都比右边子序列中的数据小,然后对左右两个子序列继续进行排序,直到整个序列有序。

原理

对于要排序的数组,首先任意选取一个数据(通常为首元素)作为关键数据,将序列中所有比该元素小的元素都放到它的左边,将所有比它大的元素都放到它的右边,再对左右两边分别用同样的方法直到每一个待处理的序列长度为1,排序结束

例如:

#include<iostream>
using namespace std;
void QuickSort(int a[],int low,int high)
{
    if(low>=high) return;//此时已经完成排序,直接返回
    int i = low;
    int j = high;
    int key = a[low];
    while(i<j)//实现第一趟排序
    {
        while(i<j&&key<a[j]) j--;//从右向左找比key小的值
        a[i] = a[j];
        while(i<j&&key>a[i]) i++;//从左向右找比key大的值
        a[j] = a[i];
    }
    a[i] = key;//将关键数据填入low=high的位置
    QuickSort(a,low,i-1);//左边子序列递归排序
    QuickSort(a,i+1,high);//右边子序列递归排序
}
int main()
{
    int a[] = {3,5,8,2,9,1};
    int num = 6;
    QuickSort(a,0,num-1);
    for(int i = 0;i<num;i++)
        cout<<a[i]<<" ";//输出1 2 3 5 8 9
    return 0;
}

1.5、合并排序

思想

归并排序是用分治思想,分治模式在每一层递归上有三个步骤:

  • 分解(Divide):将n个元素分成个含n/2个元素的子序列。

  • 解决(Conquer):用合并排序法对两个子序列递归的排序。

  • 合并(Combine):合并两个已排序的子序列已得到排序结果。

实现逻辑

1 迭代法

  • ① 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

  • ② 设定两个指针,最初位置分别为两个已经排序序列的起始位置

  • ③ 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

  • ④ 重复步骤③直到某一指针到达序列尾

  • ⑤ 将另一序列剩下的所有元素直接复制到合并序列尾

2 递归法

  • ① 将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含两个元素

  • ② 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素

  • ③ 重复步骤②,直到所有元素排序完毕

代码实现:

迭代法:

// 归并排序
template<typename T>
void merge_sort(T arr[], int len) {
    T* a = arr;
    T* b = new T[len];
    for (int seg = 1; seg < len; seg += seg) {
        for (int start = 0; start < len; start += seg + seg) {
            int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        T* temp = a;
        a = b;
        b = temp;
    }
​
    if (a != arr) {
        for (int i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
​
    delete[] b;
}

递归法:

// 归并排序
template<typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end) {
    if (start >= end)
        return;
    int len = end - start, mid = (len >> 1) + start;
    int start1 = start, end1 = mid;
    int start2 = mid + 1, end2 = end;
    merge_sort_recursive(arr, reg, start1, end1);
    merge_sort_recursive(arr, reg, start2, end2);
    int k = start;
    while (start1 <= end1 && start2 <= end2)
        reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
    while (start1 <= end1)
        reg[k++] = arr[start1++];
    while (start2 <= end2)
        reg[k++] = arr[start2++];
    for (k = start; k <= end; k++)
        arr[k] = reg[k];
}

// merge_sort
template<typename T>
void merge_sort(T arr[], const int len) {
    T reg[len];
    merge_sort_recursive(arr, reg, 0, len - 1);
}
举报

相关推荐

0 条评论