6大常用基础算法

6大常用基础算法

1 冒泡排序(BubbleSort)

基本思想

两个数比较大小,比较大的数下沉,比较小的数冒起来。

时间复杂度 O(n)2

代码

```
int a[]={1 5,4,3,2,8,0,7};
int length=sizeof(a)/size(a[0]);
void asd(int a[],int length){
    int temp;
    for(int i=0;i<length-1;i++){
        for(int j=length-1;j>i;j--){
            if(a[i]>a[j]){
                temp=a[j];
                a[j]=a[i];
                a[i]=temp;
            }
        }
    }
}
```

优化

针对问题

​ 暑假的顺序排好之后,冒泡算法仍然会继续进行下一轮比较。

方案

​ 设置标志位flag ,如果发生了交换flag设置为true:如果没有,设置为false。

​ 这样当一轮比较结束后,如果flag仍然为false,及这一轮没有发生交换,说明数据顺序已经排好,没必要继续进行下去。

代码

int a[]={1 5,4,3,2,8,0,7};
int length=sizeof(a)/size(a[0]);
void asd(int a[],int length){
    int temp;
    boolean flag;
    for(int i=0;i<length-1;i++){
        flag=false;
        for(int j=length-1;j>i;j--){
            if(a[i]>a[j]){
                temp=a[j];
                a[j]=a[i];
                a[i]=temp;
                flag=true;
            }
        }
        if(flag==false)
            break;
    }
}

​ 二分查找即折半查找,是一种相对效率较高的查找方式,但是该算法要求线性表必须采用顺序存储结构,而 且表中元素按关键字有序排列。

算法要求

​ 1 必须采用顺序存储结构。

​ 2 必须按关键字大小有序排列。

时间复杂度 O(log2n)

基本思想

​ 首先,将表中元素按照升序或降序排列。

​ 将表中间位置记录的关键字与查找的关键字相比较,如果二者相等,则查找成功;

​ 否则 利用中间位置记录,将表分成前后两个子表,根据中间关键字与查找的关键字的大小,判断查找前后表。

​ 重复以上过程,直到找到满足条件的关键字,使其查找成功,或者子表不存在为止,此时查找不成功。

二分代码模板1

int binarySearch(vector<int>& nums, int target){
  if(nums.size() == 0)
    return -1;

  int left = 0, right = nums.size() - 1;
  while(left <= right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid - 1; }
  }

  // End Condition: left > right
  return -1;
}

模板1是二分查找最基础和最基本的形式,是二分的标准模板,该模板可以通过访问数据中的单个索引来确定的元素或条件。

关键属性

二分查找的最基础和最基本的形式。
查找条件可以在不与元素的两侧进行比较的情况下确定(或使用它周围的特定元素)。
不需要后处理,因为每一步中,你都在检查是否找到了元素。如果到达末尾,则知道未找到该元素。

区分语法

初始条件:left = 0, right = length-1
终止:left > right
向左查找:right = mid-1
向右查找:left = mid+1

二分查找模板二

int binarySearch(vector<int>& nums, int target){
  if(nums.size() == 0)
    return -1;

  int left = 0, right = nums.size();
  while(left < right){
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){ return mid; }
    else if(nums[mid] < target) { left = mid + 1; }
    else { right = mid; }
  }

  // Post-processing:
  // End Condition: left == right
  if(left != nums.size() && nums[left] == target) return left;
  return -1;
}

模板二是高级模板,它用于查找需要访问数组中当前索引及其直接右邻居索引的元素·11或条件

关键属性

一种实现二分查找的高级方法。
查找条件需要访问元素的直接右邻居。
使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
保证查找空间在每一步中至少有 2 个元素。
需要进行后处理。 当你剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。

区分语法

初始条件:left = 0, right = length
终止:left == right
向左查找:right = mid
向右查找:left = mid+1

二分查找模板三

int binarySearch(vector<int>& nums, int target){
    if (nums.size() == 0)
        return -1;

    int left = 0, right = nums.size() - 1;
    while (left + 1 < right){
        // Prevent (left + right) overflow
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) {
            return mid;
        } else if (nums[mid] < target) {
            left = mid;
        } else {
            right = mid;
        }
    }

    // Post-processing:
    // End Condition: left + 1 == right
    if(nums[left] == target) return left;
    if(nums[right] == target) return right;
    return -1;
}

模板三用于搜索需要访问当前索引及其在数字中的直接左右邻居索引的元素或条件。

关键属性

实现二分查找的另一种方法。
搜索条件需要访问元素的直接左右邻居。
使用元素的邻居来确定它是向右还是向左。
保证查找空间在每个步骤中至少有 3 个元素。
需要进行后处理。 当剩下 2 个元素时,循环 / 递归结束。 需要评估其余元素是否符合条件。

区分语法

初始条件:left = 0, right = length-1
终止:left + 1 == right
向左查找:right = mid
向右查找:left = mid

3 快速排序(Quicksort)

基本思想

​ 1 从数列中取一个数作为key值

​ 2 将比这个数小的数全部放在他左边,大于等于他的数放在右边

​ 3对左右两个小数列重复第二步操作,直至各区间只有一个数

代码

//快速排序(从小到大)
void quickSort(int left, int right, vector<int>& arr)
{
	if(left >= right)
		return;
	int i, j, base, temp;
	i = left, j = right;
	base = arr[left];  //取最左边的数为基准数
	while (i < j)
	{
		while (arr[j] >= base && i < j)
			j--;
		while (arr[i] <= base && i < j)
			i++;
		if(i < j)
		{
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	//基准数归位
	arr[left] = arr[i];
	arr[i] = base;
	quickSort(left, i - 1, arr);//递归左边
	quickSort(i + 1, right, arr);//递归右边
}


//快速排序(从大到小)
void quickSort(int left, int right, vector<int>& arr)
{
	if(left >= right) //递归边界条件
		return;
	if(left < 0 || right >= arr.size())
	{
		cout << "error args! array bound." << endl;
		return;
	}//非法输入判断,防止数组越界
	int i, j, base, temp;
	i = left, j = right;
	base = arr[left];  //取最左边的数为基准数
	while (i < j)
	{
		while (arr[j] <= base && i < j)
			j--;
		while (arr[i] >= base && i < j)
			i++;
		if(i < j)
		{
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
	}
	//基准数归位
	arr[left] = arr[i];
	arr[i] = base;
	quickSort(left, i - 1, arr);//递归左边
	quickSort(i + 1, right, arr);//递归右边
}

4 希尔排序(Shell Sort)

基本思想

在要排序的一组数中,根据某一增量分为若干子序列,并对子序列分别进行插入排序。
然后逐渐将增量减小,并重复上述过程。直至增量为1,此时数据序列基本有序,最后进行插入排序。

时间复杂度 O(n1.5)

代码

int arr[] = {34, 27, 55, 8, 97};
int length = sizeof(arr)/sizeof(arr[0]);

// Shell排序算法
void shellSort(int arr[], int length)
{
    int temp = 0;
    int incre = length;
    
    while(true){
        incre = incre/2;
        
        // 根据增量分为若干子序列
        for(int k = 0;k<incre;k++){    
            
            // 对每个子序列进行插入排序
            for(int i=k+incre;i<length;i+=incre){
                
                // 在子序列中进行插入排序
                for(int j=i;j>k;j-=incre){
                    
                    // 如果当前元素比前一个元素小,交换位置
                    if(arr[j]<arr[j-incre]){
                        temp = arr[j-incre];
                        arr[j-incre] = arr[j];
                        arr[j] = temp;
                    }else{
                        break;
                    }
                }
            }
        }
        
        // 当增量减为1时结束排序
        if(incre == 1){
            break;
        }
    }
}

5 选择排序(SelctionSort)

基本思想

在长度为n的无序数组中,第一次遍历n-1个数,找到最小的数与第一个元素交换,

第二次便利n-2个数,找到最小值与第二个元素交换;

循环上述操作,直到第n-1此遍历,找到最小的数值与n-1个元素交换,排序完成。

代码

int arr[] = {34, 27, 55, 8, 97};
int length = sizeof(arr)/sizeof(*arr);
selectSort(arr, length);
//
/// 以小到大排序
void selectSort(int arr[], int length)
{
    for (int i = 0; i < length - 1; i ++) {
        int minIndex = i;
        for (int j = i + 1; j < length; j ++) {
            if (arr[minIndex] > arr[j]) {
                minIndex = j;
            }
        }
        
        /// 找到最小值,进行替换
        if (minIndex != i) {
            int temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
}

6 插入排序(Insertion Sort)

基本思想

在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。

时间复杂度O(n2)

代码

int arr[] = {34, 27, 55, 8, 97};
int length = sizeof(arr)/sizeof(*arr);
insertSort(arr, length);


/// 以小到大
void insertSort(int arr[], int length)
{
    for (int i = 0; i < length - 1; i ++) {
        for (int j = i + 1; j > 0; j --) {
            if (arr[j] < arr[j - 1]) {
                int temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
            } else { // 当第j-1个数据小于第j个数据时,后面的也就都小于,没必要再遍历
                break;
            }
        }
    }
}

posted @ 2023-07-20 11:21  小小浑鱼  阅读(194)  评论(0)    收藏  举报