[C++] Ten classic sorting algorithm codes and ideas

You can use leetcode question 88 to verify whether the sorting algorithm you wrote is correct
88. Merge two ordered arrays

The code is as follows:
Note that the following version is written on VS. When writing 88 questions, you need to copy the array elements of nums2 to the second half of the nums1 array, and then call these sorting functions

using namespace std;
# include<iostream>
# include<vector>


//打印数据
void print_vec(const vector<int>& vec) {
    
    
	for (auto it = vec.begin(); it != vec.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

// 冒泡排序 稳定排序  时间复杂度O(n*n),空间复杂度O(1)
void bubbleSort(vector<int>& vec) {
    
    
	// 两两比较
	int n = vec.size();
	for (int i = 0; i < n; i++) {
    
    
		for (int j = 0; j < n - i - 1; j++) {
    
    
			if (vec[j] > vec[j + 1]) swap(vec[j], vec[j + 1]);
		}
	}
}


// 插入排序 稳定排序  时间复杂度O(n*n),空间复杂度O(1)
void insertSort(vector<int>& vec) {
    
    
	// 每次将新元素插入到已排序的有序队列里面
	int n = vec.size();
	for (int i = 1; i < n; i++) {
    
    
		if (vec[i] > vec[i - 1]) continue;
		int temp = i;//记录新元素每次交换后的位置
		for (int j = i - 1; j >= 0; j--) {
    
    

			if (vec[temp] < vec[j]) {
    
    //只要比排序数小,就交换两者位置
				swap(vec[temp], vec[j]);
				temp = j;//记录新元素的位置
			}
			else break;
		}

	}
}


//归并排序 稳定排序 时间复杂度O(n*logn),空间复杂度O(n)
//算法思想
//1、把长度为n的输入序列分成两个长度为n / 2的子序列;
//2、对这两个子序列分别采用归并排序;
//3、 将两个排序好的子序列合并成一个最终的排序序列。
void mergeSort(vector<int>& vec,vector<int> &data,int start,int end) {
    
    
	//vec为需要排序的数组,data为放置排序好的子序列的数组,取闭区间[start,end]
	if (start >= end) return;
	int mid = start + (end - start) / 2;
	mergeSort(vec, data, start, mid);
	mergeSort(vec, data, mid + 1, end);

	//p1为前半个数组的头指针,p2为后半个数组的头指针,p为data数组的头指针
	int p1 = start, p2 = mid + 1, p = start;
	//int len = (end - start) * 2;
	for (; p <= end; p++) {
    
    
		//这里用if进行判断的时候很重要,容易把情况漏掉
		//刚开始我写成if(p1<=mid&&vec[p1]<vec[p2]){} else{}  ,这样写漏掉了一些情况
		if (p1<=mid&&p2>end) {
    
    
			data[p] = vec[p1++];
		}
		else if(p1>mid&&p2<=end){
    
    
			data[p] = vec[p2++];
		}
		else {
    
    //两个都没越界
			data[p] = vec[p1] > vec[p2] ? vec[p2++] : vec[p1++];
		}
	}
	for (int i = start; i <= end; i++) {
    
    
		vec[i] = data[i];
	}

}


// 快速排序 不稳定排序  时间复杂度O(n*log n),空间复杂度O(logn)(递归会使用栈)
//1、选取第一个数为基准
//2、将比基准小的数交换到前面,比基准大的数交换到后面
//3、对左右区间重复第二步,直到各区间只有一个数
void quickSort(vector<int>& vec,int index_start,int index_end) {
    
    
	//使用递归 传入整个数组和需要处理的数据起始位置[index_start,index_end]
	
	if (index_end <= index_start) return;//递归终止条件

	int temp = index_start;//选取第一个数为基准
	for (int i = temp + 1; i <= index_end;i++ ) {
    
    
		if (vec[i] < vec[temp]) {
    
    
			for (int j = i; j > temp; j--) {
    
    
				//vec[i]依次和temp开始一直到i-1位置的数进行交换,直到i位置数字换到vec[temp]前面去
				swap(vec[j], vec[j - 1]);//两两交换
				
			}
			temp++;//记录基准数更新后的位置
		}

	}
	quickSort(vec, index_start, temp - 1);
	quickSort(vec, temp + 1, index_end);

}

// 希尔排序 不稳定排序  时间复杂度O(n*n),空间复杂度O(1)
// 插入排序的变种,局部有序
void insert_sort(vector<int>&vec, int gap,int start_index) {
    
    //将start_index插入到本组中正确的位置
	int insert_num = vec[start_index];
	int i = start_index - gap;
	for (; i >=0&&vec[i]>insert_num; i=i-gap) {
    
    
		vec[i + gap] = vec[i];
	}
	vec[i + gap] = insert_num;
}
void shellSort(vector<int>& vec) {
    
    
	
	for (int gap = vec.size() / 2; gap >= 1; gap /= 2) {
    
    
		for (int j = gap; j < vec.size(); j++) {
    
    
			insert_sort(vec, gap, j);
		}
	}


}

// 选择排序 不稳定排序  时间复杂度O(n*n),空间复杂度O(1)
void selectSort(vector<int>& vec) {
    
    
	//每次选择剩余元素里面的最小值放到第一个循环的位置上
	int n = vec.size();
	for (int i = 0; i < n; i++) {
    
    
		int minNum = i;
		for (int j = i + 1; j < n; j++) {
    
    
			if (vec[minNum] > vec[j]) minNum = j;;
		}
		swap(vec[i], vec[minNum]);
	}
}


// 堆排序 不稳定排序  时间复杂度O(n*logn),空间复杂度O(1)
//堆排序的基本思想是:
//将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。
//将其与末尾元素进行交换,此时末尾就为最大值。
//然后将剩余n - 1个元素重新构造成一个堆,这样会得到n个元素的次小值。
//如此反复执行,便能得到一个有序序列了
//void heapify(vector<int>& vec, int index) {
    
    
//
//}
void adjust_maxheap(vector<int>& vec,int end) {
    
    //调整为大顶堆
	//end为需要调整的最大位置,闭区间[0,end]
	//节点i的父节点:(i-1)/2  左孩子节点:2i+1,右孩子节点:2i+2

	for (int i = (end - 1) / 2; i >= 0; i--) {
    
    //(end-1)/2为倒数第二层的右边最后一个非叶子结点
		//其实就是每次选择非叶子结点和它的孩子节点为一组,
		//把这组节点的最大值找出来当做父节点,再从右往左,从下到上依次循环操作
		int left = 2 * i + 1;
		int right = 2 * i + 2;
		if (right > end) {
    
    
			//只有左孩子节点
			//这种情况最多出现一次
			if (vec[left] > vec[i]) {
    
    
				swap(vec[left], vec[i]);
			}
		}
		else {
    
    //两个孩子节点都有
			int index = vec[left] > vec[right] ? left : right;
			if (vec[index] > vec[i]) {
    
    
				swap(vec[index], vec[i]);
			}
		}

	}
}
void heapSort(vector<int>& vec) {
    
    
	for (int i = 0; i < vec.size()-1; i++) {
    
    
		adjust_maxheap(vec, vec.size()-1 - i);
		swap(vec[0], vec[vec.size() - 1 - i]);//把调整好的大顶堆的第一个值和end进行交换

	}
}


// 计数排序
void countSort(vector<int>& vec) {
    
    

}

int main() {
    
    
	vector<int> vec{
    
     10,8,4,6,9,10,123,6,2,14,3,8,5 };

	//cout << "------快速排序-------" << endl;
	//quickSort(vec,0,vec.size()-1);
	//print_vec(vec);

	//cout << "------归并排序-------" << endl;
	//vector<int> data(vec.size(), 0);
	//mergeSort(vec,data,0,vec.size()-1);
	//print_vec(data);

	cout << "------堆排序-------" << endl;
	heapSort(vec);
	print_vec(vec);

	return 0;

}

Guess you like

Origin blog.csdn.net/qq_43050258/article/details/130029079