6.简单选择排序,堆排序,桶排序,(基础数据结构)

一.简单选择排序和堆排序

选择排序:每次从待排序队列中找到最小值,和待排序队列的第一位交换即可
在这里插入图片描述
选择排序具体实现代码:

//时间复杂度O(n^2) 空间复杂度O(1) 不稳定的 
void SelectSort(int arr[], int len) 
{ 
    //assert int minindex;
    //存放最小值的下标
    for(int i=0; i<len-1; i++) 
    { 
        minindex = i;
        //循环开始前先认为待排序队列的第一个值是最小值 
        for(int j = i+1; j<len; j++) 
        { 
            if(arr[minindex] > arr[j]) 
            { 
                minindex = j; 
            } 
        }
        if(minindex != i)
            //这个if判断可以省略,不影响 
        { 
            int tmp = arr[minindex]; 
            arr[minindex] = arr[i];
            arr[i] = tmp; 
        }
    } 
}

二.堆排序:

堆分为两种:大顶堆和小顶堆 两个统称为堆
大顶堆:一个二叉树,父节点的值大于子节点的值
小顶堆:一个二叉树,父节点的值小于子节点的值
什么是树形结构:
二叉树,树根,深度,叶子结点,左孩子,右孩子,完全二叉树,满二叉树
深度怎么求:logn+1
大顶堆和小顶堆的关系,和兄弟节点的值无关,只和父子节点有关
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
调整2个要点:
1.从最后一个非叶子节点子树开始从后向前调整
2.调整的时候顺序是从上向下
3.升序(大顶堆),降序(小顶堆)

在这里插入图片描述
堆排序具体实现代码:

static void HeapAdjust(int arr[], int start, int end)
//时间复杂度O(logn) 空间 复杂度O(1)
{ 
    int tmp = arr[start];
    for(int i=2*start+1; i<=end; i=i*2+1)
        //i? 堆排序效率高体现在这里i=i*2+1 
    { 
        //1.左右孩子都存在
        //2.只有左孩子,没有右孩子 
        if(i<end && arr[i] < arr[i+1])
            //通过i<end保证右孩子存在,且arr[i] <arr[i+1]保证左孩子小于右孩子 
        { 
            i++;//这时候让i指向较大的右孩子下标
        }
        //if判断失败的话,要么没有右孩子,要么有右孩子但是左孩子比右孩子值大,所以i不需要 改变
        if(arr[i] > tmp)//判断较大孩子节点的值是否比父节点的值大,大的话向上覆盖,不然 就找到了合适位置 
        { 
            arr[start] = arr[i]; start = i; 
        }
        else 
        { 
            break;//左右孩子中较大的孩子值小于tmp 
        }
    }
    arr[start] = tmp;//有两种情况执行到这一行代码:1.触底 2.找到放tmp的合适位置 
}
//堆排序的时间复杂度O(nlogn) 空间复杂度O(1) 不稳定 
void HeapSort(int arr[], int len) 
{
    //assert 
    //2.调整为大顶堆 
    for(int i=(len-1-1)/2; i>=0; i--)//O(nlogn)
    { 
        HeapAdjust(arr, i, len-1); 
    }
    //第一个for循环走出来,这时已经为大顶堆了
    int tmp = 0; for(int j=0; j<len-1; j++) //j指的是循环的次数(顶部数据和最后一个节点交换的次 数)//O(nlogn) 
    {//3.将顶部数据和最后一个节点进行了交换
        tmp = arr[0]; 
        arr[0] = arr[len-1-j];
        arr[len-1-j] = tmp;//已经将顶部数据和最后一个节点进行了交换
        //4.重复2.3操作
        HeapAdjust(arr, 0, (len-1-j)-1); 
    }
}

三.桶排序

基数(桶)排序,低位优先,所有数据从地位开始,依次放入对应的10个桶内,再依次从桶中将数据取出(循环次数和最大值的位数有关),直到所有数据全部有序。
在这里插入图片描述
此时,完全有序。
循环的次数和最大值的位数有关
第七种排序算法:基数(桶)排序, 低位优先,所有数据从低(个)位开始,依次放入到对应的10个桶内(入队),再依次从桶中将数据依次取出(出队),直到所有数据全部有序。 循环的次数和最大值的位数有关。 时间复杂度O(dn) 空间复杂度O(n) 不稳定
基数(桶)排序具体实现代码:

//获取数组中最大值的位数 
static int Get_Figure(int arr[], int len) 
{ 
	int max = 0;
	for(int i=0; i<len; i++) 
	{ 
		if(arr[i] > max) 
		{
			max = arr[i];
		} 
	}
	int count = 0;
	while(max != 0) 
	{ 
		count++; max /= 10;
	}
	return count; 
}
//获取n的第fin位的值 
//1234,2 = 2 
//234,0 = 4 
//12345,4 = 1 
//12345,7 = 0 
static int Get_num(int n, int fin)
{ 
	for(int i=0; i<fin; i++)
	{
		n = n / 10;
	}
	return n % 10;
	//return n/(int)(pow((double)10, fin)) % 10; 
}
static void Radix(int arr[], int len, int fin)
//二维数组 fin判断的依据,到底是 以什么位排序
//时间复杂度O(n) 空间复杂度O(n) 
{ 
	int bucket[10][20] = {0};
	//桶 
	int num[10] = {0};
	//对应的桶中有多少个有效值 
	//所有的数据都以fin位为依据,放到了桶内 
	for(int i=0; i<len; i++)
		//数组的下标 从0开始放 
	{ 
		int index = Get_num(arr[i], fin);
		//获取arr[i]的fin位的值,找到对应的桶
		bucket[index][num[index]] = arr[i];
		//放到对用的桶中第num[index]位上
		num[index]++;
		//对应的桶中有效个数++ 
	}
	//从0-9桶内依次取值到arr里 
	int k = 0;
	for(int i=0; i<10; i++)
		//几号桶 
	{
		for(int j=0; j<num[i]; j++)
			//j桶中有效值个数
		{ 
			arr[k++] = bucket[i][j];
		} 
	}
}
static void Radix_queue(int arr[], int len, int fin)
//时间复杂度O(n) 空间复 杂度O(n)
{
	LQueue queArr[10];
	for(int i=0; i<10; i++) 
	{ 
		InitLQueue(&queArr[i]);
	}
	for(int i=0; i<len; i++) 
	{
		int index = Get_num(arr[i], fin);
		Push(&queArr[index], arr[i]); 
	}
	int k = 0;
	for(int i=0; i<10; i++) 
	{
		while(!IsEmpty(&queArr[i])) 
		{
			Pop(&queArr[i], &arr[k++]);
		}
	}
	for(int i=0; i<10; i++)
	{
		Destroy(&queArr[i]);
	} 
}
void RadixSort(int arr[], int len)
//时间复杂度O(dn) 空间复杂度(n)稳定
{ 
	//assert
	int count = Get_Figure(arr, len);
	for(int i=0; i<count; i++)
		//循环的趟数,低位优先
	{
		Radix_queue(arr, len, i); 
	} 
}

四. 快速排序

每次找到基准值,以基准值为分界线,将数据分成两块,左边的数据都比基准值小,右边的数据都比基准值大
规则:
1.从右向左找比基准值小的数据,找到后,向左挪动
2.从左向右找比基准值大的数据,找到后,向右挪动
3.重复1,2,直到left ==right,结束,将基准值放到arr[left] 或者arr[right]内
**第八种排序算法:**快速排序,越有序越慢,每次找到基准值,以基准值为分界线,将数据分成两块,左边的数据都比基准值小,右边的数据都比基准值大
规则:
1.从右向左找比基准值小的数据,找到后,向左挪动
2.从左向右找比基准值大的数据,找到后,向右挪动
3.重复1,2,直到left = right,结束,将基准值放到arr[left] 或者arr[right]内
缺点:越有序越慢,不稳定
在这里插入图片描述
在这里插入图片描述
快速排序具体实现代码:

static int Partition(int arr[], int left, int right) 
{
	int tmp = arr[left]; 
	while (left < right)
		//进来保证有两个值 
	{ 
		while(left < right && arr[right] > tmp) 
			right--; 
		if(left == right) 
		{
			break; 
		}
		arr[left] = arr[right];
		while(left < right && arr[left] <= tmp)
			left++; 
		if(left == right) 
		{ 
			break;
		}
		arr[right] = arr[left]; 
	}
	arr[left] = tmp;
	//arr[right] = tmp; return left;
	//return right; 因为此时left == right
}
static void Quick(int arr[], int left, int right) 
{
	//第一种优化:如果有效个数特别少,直接调用直接插入排序 
	//第二种优化:三数取中
	//第三种优化:防止完全有序,自己打乱一下 
	/*if(left < right) 
	{ 
	   int midindex = Partition(arr, left, right); 
	   if(left < midindex-1)
	   { 
	      Quick(arr, left, midindex-1); 
	   }
	   if(midindex+1 < right) 
	   { 
	       Quick(arr, midindex+1, right); 
	   } 
	}*/ 
	if(left < right) 
	{ 
		int midindex = Partition(arr, left, right); 
		Quick(arr, left, midindex-1);
		Quick(arr, midindex+1, right);
	}
}
static void Quick_stack(int arr[], int left, int right) 
{ 
	stack<int> st; 
	if(left < right)
	{ 
		int midindex = Partition(arr, left, right); 
		if(left < midindex-1) 
		{ 
			st.push(left);
			st.push(midindex-1);
		}
		if(midindex+1 < right) 
		{ 
			st.push(midindex+1);
			st.push(right); 
		} 
	}
	while(!st.empty())
	{ 
		int q = st.top();
		st.pop();
		int p = st.top();
		st.pop(); 
		int midindex = Partition(arr, p, q); 
		if(p < midindex-1)
		{
			st.push(p);
			st.push(midindex-1);
		}
		if(midindex+1 < q) 
		{
			st.push(midindex+1);
			st.push(q);
		}
	}
}
void QuickSort(int arr[], int len)
//时间复杂度O(nlogn) 空间复杂度O(1) 不稳定
{ 
	//assert 
	Quick_stack(arr, 0, len-1); 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值