########关于c++数组的理解
给定一个数组int array[10] = {9,8,7,10,6,1,0,'\0'};
可以直接用int length = sizeof(array)/sizeof(array[0]); 求得数组的长度,求得长度的操作一定要在数组被当做参数传递之前进行。
例如:如果通过一个求数组长度的函数来求数组长度
int getArrayLength(int array[])
{
int length = sizeof(array)/sizeof(array[0]);
//这样求得的length永远是2,sizeof(array)永远都是指针的大小,是8;
}
########插入排序的几种思想
1和2都是直接插入排序,时间复杂度有些区别
1.假设第一个数据是有序的,把之后的每个数据都和前面的数据比较,如果带插入数据比当前比较的数据小就交换位置
for(i; i<6-1; i++)
{
int j = i;
while(array[j+1] < array[j] && j >= 0)
{
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
j--;
}
}
2.把需要插入的数据拿出来放在旁边,然后把它和它前面的数据比较,比它大的数据,就往后一次移动一位,最后把带插入的数据放在空的位置上。
for(i; i<arrayLength-1; i++)
{
int j=i+1;
int insertNum = array[j];
while(j>0 && insertNum < array[j-1])
{
array[j] = array[j-1];
j--;
}
array[j] = insertNum;
}
3.二分法插入排序,通过二分法把需要插入位置,然后移动其它的数据,把它插到对应的位置
for (int i=1; i<array.length; i++) {
temp = array[i];
left = 0;//重点,必须在在for循环条件的内部,保证每一次都要在数组的最左端开始,否则无法排序
right = i-1;
while(left <= right) {//先找出需要插入的位置
mid = (left+right)/2;
if(temp < array[mid]) {//因为i的左边都是有序的,所以temp比中间的小,就会比mid到i之间的数字都小
right = mid -1;
} else {
left = mid +1;
}
}
//通过上面的while循环找到需要插入的数据,应该插入的位置,然后移动其他的数据,把temp插入到对应的位置上面
for (int j=i-1; left<=j; j--) {//把temp插入到left的位置,j是比left要大的数字
array[j+1] = array[j];
}
if(left != i) {
array[left] = temp;
}
}
for (i = 1; i<length; i++) {
right = i-1;
int temp = array[i];
while (left <= right) {
mid = (left+right)/2;
if (temp < array[mid]) {
right = mid-1;
} else {
left = mid + 1;
}
}
for (j=i-1; j>=left; j--) {
array[j+1] = array[j];
}
array[left] = temp;
}
4.希尔排序(https://blog.csdn.net/weixin_37818081/article/details/79202115)
希尔排序是插入排序的一种,希尔排序又叫做缩小增量排序,该方法的基本思想是:
假设一个元素序列有n个元素,首先取一个整数作为增量Hibbard,取增量的方式有多种,length/3+1,length/2等等,
然后把所有元素之间距离为Hibbard的元素放在同一个子序列中,直到Hibbard的值为1,将所有的元素放在同一个子序列为止。
int dk = length;
while(dk > 1)
{
dk = dk/3 + 1;
int i;
for(i = dk; i<length; i++)
{
int temp = array[i];
j = i-dk;// *******很重要,从第一个开始,如果是j=i的话很容易出错误
while(j>=0 && array[j]>temp) //和*****temp****进行比较,比temp大的数都要往后移动到相应的位置,并不是交换
{
array[j+dk] = array[j];
j -= dk;
}
array[j+dk] = temp;
}
}
########选择排序
1.简单选择排序
原理,每一次都在数组中找出最小,或者最大的数,记住它的下标k,然后把它赋值给min或者max,然后先把最左边的插入位置的元素放到k位置,然后把min或者max放到最左边
for (int i=0; i<length; i++)
{
int k = i;
int min = array[i];
for(int j=i; j<length-1; j++)
{
if(min > array[j+1]) //一点要和min进行比较,这样才能求得最小值, array[j] > array[j+1]; min = array[j+1]; 这样找不出最小值,是行不通的,一定要注意
{
min = array[j+1];
k=j+1;
}
}
array[k] = array[i];
array[i] = min;
}
2.复杂的选择排序,堆排序(https://www.cnblogs.com/chengxiao/p/6129630.html)
https://my.oschina.net/JKOPERA/blog/1927611
首先介绍一下节点的下标:i节点的父节点下标就为(i-1)/2,它的左右子节点下标分别为2*i+1和2*i+2;如第0个节点左右子节点下标分别为1和2。
调整堆function
void adjustHeap(int array[], int parent, int length){
int temp = array[parent];
int child = 2*parent +1;//先获得左孩子节点
while(child < length){
if(child+1<length && array[child]<array[child+1]){ //如果左节点的值小于右节点的值,就选中右节点
child++;
}
if(temp >= array[child]){ //------------应该是temp 而不是 array[parent]
break; //如果选中的节点比父节点小,就结束,不需要交换
}
//如果选中的节点,大于父节点,就把它赋值给父节点
array[parent] = array[child];
//然后以子节点作为父节点,调整下一个节点
parent = child;
child = 2*parent +1;
}
//最后把temp放到子节点最后停留的位置parent = child;
array[parent] = temp;
}
//构建大顶堆&&交换堆顶与末尾的元素
void heap_Sort(int array[], int length){
for(int i=length/2-1; i>=0; i--){ ----------------------------这个地方i一定是可以取到0的
adjustHeap(array,i,length);
}
for(int i=length-1; i>0; i--){
int temp = array[i];
array[i] = array[0];
array[0] = temp;
//调整堆的结构,把最大值保存下来,得到i-1个元素的堆,把最大的数据保留下来,然后构建调整为大顶堆
adjustHeap(array,0,i);
}
}
########交换排序
1.冒泡排序
对整个数组进行遍历,把最大的元素通过交换的方式放在最后面,然后进行下一次遍历,找到最大,一次循环
for(int i=0; i<length-1; i++){
for(int j=0; j<length-i-1; j++){
if(array[j] > array[j+1]){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
2.快速排序
以数组中的一个元素为基准,调整数组的顺序,把比基准元素小的放在它左边,比它大的放在右边,记录最后基准元素的位置,然后分别给它的左边和右边进行之前相同的操作
然后依次递归,直到排序完成
int getMiddle(int a[], int low, int high)
{
int temp = a[low];// 基准元素
while (low < high)
{
// 找到比基准元素小的元素位置
while (low < high && a[high] >= temp) 一定要注意这个地方包含等号,相等的时候不移动
{
high--;
}
a[low] = a[high];
while (low < high && a[low] <= temp)
{
low++;
}
a[high] = a[low];
}
a[low] = temp;
return low;
}
void quickSort(int a[], int low, int high){
if (low < high)
{ // 如果不加这个判断递归会无法退出导致堆栈溢出异常
int middle = getMiddle(a, low, high);
quickSort(a, 0, middle - 1);
quickSort(a, middle + 1, high);
}
}
########归并排序
基本思想:归并排序是将两个或两个以上有序表合并成一个新的有序表,即把待排序列分为若干个子序列,每个子序列是有序的,然后再把有序的子序列合并为整体的有序序列
https://www.cnblogs.com/chengxiao/p/6194356.html
void merge(int arr[],int left,int mid,int right,int temp[]){
int i = left;//左序列指针
int j = mid+1;//右序列指针
int t = 0;//临时数组指针
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t++] = arr[i++];
}else {
temp[t++] = arr[j++];
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while(left <= right){
arr[left++] = temp[t++];
}
}
void sort(int arr[],int left,int right,int temp[]){
if(left<right){
int mid = (left+right)/2;
sort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
sort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
}
}
c语言
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
int i = startIndex, j=midIndex+1, k = 0;
while(i!=midIndex+1 && j!=endIndex+1)
{
if(sourceArr[i] > sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1)
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
k = 0;
for(i=startIndex; i<=endIndex; i++)
sourceArr[i] = tempArr[k++];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
int midIndex;
if(startIndex < endIndex)
{
midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
########基数排序
https://www.cnblogs.com/kkun/archive/2011/11/23/2260275.html
https://baike.baidu.com/item/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F/7875498?fr=aladdin
LSD基数排序的基本步骤: (LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。)
1.找出数组中的最大的数,然后通过最大数的位数,判断再次分配的次数
2.求得每个元素个位十位百位的数是多少, 通过求余数把它们求出来,各位:(798/1) %10 = 8 十位: (798/10) %10 = 9 百位: (798/100) %10 = 7
3.然后首先通过个位数的数字,把元素放入到对应的桶中
4.然后把它们按桶的大小顺序,从小到大依次取出,现在的数个位数就是有序的了
5.然后再通过十位数的数字,把元素依次放入到对应的桶中,因为个位数已经是有序的了,现在十位数也是有序的了
如果没有百位数,就到此为止,取出所有的数据,就是已经排序完成了
////获取数组中的最大数
int getMaxNum(int array[], int length) {
int maxNum = 0;
for (int i=0; i<length; i++) {
if (maxNum < array[i]) {
maxNum = array[i];
}
}
return maxNum;
}
//获取最大数的位数,次数也是再分配的次数。
int getLoopTimes(int maxNum) {
int count = 1;
int temp = maxNum / 10;
while (temp != 0) {
count ++;
temp = temp / 10;
}
return count;
}
//将数字分配到各自的桶中,然后按照桶的顺序输出排序结果
void sort2(int array[], int length, int loop) {
//建立一组桶此处的20是预设的根据实际数情况修改
int buckets[10][20] = {};
//求桶的index的除数
//如798个位桶index=(798/1)%10=8
//十位桶index=(798/10)%10=9
//百位桶index=(798/100)%10=7
//tempNum为上式中的1、10、100
int tempNum = 10^(loop- 1);
for (int i=0; i<length; i++) {
int throw_index = (array[i]/tempNum) % 10;
for (int j=0; j<20; j++) {
if (buckets[throw_index][j] == 0) {
buckets[throw_index][j] = array[i];
break;
}
}
}
//将桶中的数,倒回到原有数组中
int k = 0;
for (int i=0; i<10; i++) {
for (int j=0; j<20; j++) {
if (buckets[i][j] != 0) {
array[k++] = buckets[i][j];
buckets[i][j] = 0;
}
}
}
}
void sort1(int array[], int length) {
//取得最大的数
int maxNum = getMaxNum(array, length);
//根据最大数,计算出需要分配的次数
int loopTimes = getLoopTimes(maxNum);
//对每一位进行桶分配
for (int i=1; i<=loopTimes; i++) {
sort2(array, length, i);
}
}