C语言数据结构8大排序

排序难点:算法多,容易混淆
1.直接(简单)插入排序:扑克牌

      特点:越有序越快,完全有序O(n),非常重要,这个是希尔排序的基础

 2.希尔(shell)排序
        分组后利用直接插入排序
3.冒泡排序:
        两两比较,大的往后走

* 4.快速排序:
       算法: 1.从后往前找比基准小的数字,找到往前挪
                   2.从前往后找比基准大的数字,找到往后挪
                   3.重复1.2
       缺点:1.越有序,越慢                
                  2.空间复杂度大,不稳定

  5.选择排序:
        每次都从待排序中选出最小的一个和待排序的第一个进行数据交换

  6.堆排序:
        算法:1.从最后一颗子树开始,从后往前调整
                   2.每次调整,从上往下调整
                   3.调整为大根堆
                  大根堆:在二叉树中所有的父都大于子
                  小根堆:在二叉树中所有的父都小于子
                  度:就是节点的分支
                  叶子节点:度为0
                  兄弟:同一个双亲的孩子之前被称为兄弟
                  深度:就是树的层高

  7.归并排序
            1.将两段有序的数据合并成为一段有序的数据,直到所有的数据都有序
            2.把两段有序的归并成为一段有序的,也称为2路有序
  8.基数排序(桶排序)
            局限性:不能处理负数
  9.第‘9’个排序
           链表排序
           1.单链表存放数据我们用什么排序?(冒泡,选择)
           2.双向链表存放数据我们用什么排序?(快排(STL自带的list为双向链表))
 

#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"listqueue.h"
//直接(简单)插入排序
//void InsertSort(int* arr, int len)//O(n^2),最好的情况,O(1),稳定
//{
//	int tmp;//存放当前处理的数字
//	int j;
//	for (int i = 1; i < len; i++)//从第二个数字开始
//	{//1 2 3 4 5
//		tmp = arr[i];
//		for (j = i - 1; j >= 0; j--)//从后往前找第一个比tmp小的数字
//		{
//			if (arr[j] > tmp)//arr[j]需要后移
//				arr[j + 1] = arr[j];
//			else
//				break;
//		}
//		arr[j + 1] = tmp;
//	}
//}
 
//gap:分组数
//void Shell(int* arr, int len, int gap)
//{
//	int tmp;//保存当前需要处理的值
//	int j;
//	for (int i = gap; i < len; i++)//从"第二个"元素开始
//	{
//		tmp = arr[i];
//		for (j = i - gap; j >= 0; j -= gap)
//		{
//			if (arr[j] > tmp)
//				arr[j + gap] = arr[j];
//			else
//				break;
//		}
//		arr[j + gap] = tmp;
//	}
//}
 
//希尔排序
//void ShellSort(int* arr, int len)//时间复杂度:O(n^1.3~n^1.5),空间复杂度O(1),不稳定
//{
//	int d[] = { 5,3,1 };//分组组数,注意最后一定是1.缩小增量
//	for (int i = 0; i < sizeof(d) / sizeof(d[0]); i++)
//	{
//		Shell(arr, len, d[i]);
//	}
//}
 
 
/*
void InsertSort(int* arr, int len)//O(n^2),完全有序O(n^2)这个程序写的有问题
{
	int tmp;
	int i;
	int j;
	for (i = 1; i < len; i++)//从第二个数字开始处理
	{
		tmp = arr[i];//需要处理的值
		for (j = 0; j < i; j++)//找合适的位置,太慢
		{
			if (arr[j] > tmp)
				break;
		}//1 2 3 4 5
		//把后面的数据往后移动
		for (int k = i - 1; k >= j; k--)
		{
			arr[k + 1] = arr[k];
		}
		//插入新数据
		arr[j] = tmp;
	}
}
*/
 
 
//希尔排序(时间复杂度:O(n^1.3~n^1.5),空间复杂度O(1),不稳定)
//void Shell(int* arr, int len, int gap)
//{
//	int tmp;int j;
//	for (int i = gap; i < len; i ++)
//	{
//		tmp = arr[i];
//		for ( j= i - gap; j >= 0; j -= gap)
//		{
//			if (arr[j] > tmp)
//			{
//				arr[j+gap] = arr[j];
//			}
//			else
//				break;
//		}
//		arr[j+gap] = tmp;
//	}
//}
//void ShellSort(int* arr, int len)
//{
//	int d[] = { 5,3,1 };
//	for (int i = 0; i < sizeof(d) / sizeof(d[0]); i++)
//	{
//		Shell(arr, len, i);
//	}
//}
 
 
//冒泡排序( O(n^2),O(1),稳定)
//void Bubbler(int* arr, int len)
//{
//	int temp;
//	for (int i= 0; i < len-1; i++)
//	{
//		for (int j = 0; j + 1 < len - i; j++)
//		{
//			if (arr[j] > arr[j+1])
//			{
//				temp = arr[j];
//				arr[j] = arr[j+1];
//				arr[j+1] = temp;
//			}
//		}
//	}
//}
 
 
//快速排序,O(nlogn),O(logn),不稳定
//int Partition(int* arr, int low, int high)//一次划分O(n),O(1)
//{
//	int tmp = arr[low];//基准
//	while (low<high)
//	{
//		while (low<high && arr[high]>tmp)
//		{
//			high--;
//		}
//		if(low<high)
//		{
//			arr[low] = arr[high];
//		}
//		while (low<high && arr[low]<=tmp)
//		{
//			low++;
//		}
//		if (low < high)
//		{
//			arr[high] = arr[low];
//		}
//	}
//	arr[low] = tmp;
//	return low;
//}
//
//void Quick(int* arr,int low,int high ) {
//	int par = Partition(arr, low, high);
//		if (low < par - 1)
//		{
//			Quick(arr, low, par - 1);
//		}
//		if (par + 1 < high)
//		{
//			Quick(arr, par + 1, high);
//		}
//}
//void QuickSort(int* arr, int len)
//{
//	Quick(arr, 0, len - 1);//加了一个马甲,目的为增加一个参数,解决参数不一致问题
//}
 
 
 
//void QuickSort(int* arr, int len)//不能直接递归,所以舍去
//{
//	int par=partition(arr,0,len-1)
//		if (0 < par - 1)
//		{
//			QuickSort(arr,len)
//		}
//}
 
 
//选择排序 (O(n^2),O(1),不稳定)
//void SelectSort(int* arr, int len)
//{
//	int minlndex;//最小值的下标
//	int tmp;
//	for (int i = 0; i < len - 1; i++)
//	{
//		minlndex = i;
//		for (int j = i + 1; j < len; j++)
//		{
//			if (arr[minlndex] > arr[j])
//			{
//				minlndex = j;
//			}
//		}
//		//最小值和待排序的第一个值交换
//		if (minlndex != i)
//		{
//			tmp = arr[minlndex];
//			arr[minlndex] = arr[i];
//			arr[i] = tmp;
//		}
//
//	}
//}
 
 
//堆排序
//父-->子:i-->2*i+1,2*i+2
//子-->父:i-->(i-1)/2
//void HeapAdjust(int* arr, int start, int end)
//{
//	int tmp = arr[start];
//	for (int i = 2 * start + 1; i <= end; i = 2*i+1)
//	{
//		if (i < end && arr[i] < arr[i + 1])//有右孩子,并且左孩子的值小于右孩子
//		{
//			i++;
//		}//i一定是左右孩子的最大值
//		if (arr[i] > tmp)
//	{
//		arr[start] = arr[i];
//		start = i;
//	}
//		else
//		{
//			break;
//		}
//	}
//	arr[start] = tmp;
//}
//
//void HeapSort(int* arr, int len)
//{
//	//第一次建立大根堆,从后往前,多次调整
//	int i;
//	for (i = (len - 1 - 1) / 2; i >= 0; i--)
//	{
//		HeapAdjust(arr, i, len - 1);
//	}
//	//每次将根和待排序的最后一个做交换,然后再做调整
//	int tmp;
//	for (i = 0; i < len; i++)
//	{
//		tmp = arr[0];
//		arr[0] = arr[len - 1 - i];
//		arr[len - 1 - i] = tmp;
//
//		HeapAdjust(arr, 0, len - 1 - i-1);
//	}
//
//}
 
 
 
//归并有序O(nlogn),O(n),稳定
// 一次归并 O(n)
//void Merge(int* arr, int len, int gap)
//{
//	int low1 = 0;//第一段起始下标,
//	int high1 = low1 + gap-1;//第一段归并段的结束下标
//	int low2 = high1 + 1;//第二个归并段的起始下标
//	int high2 = low2 + gap-1<len-1?low2+gap-1:len-1;//第二个归并段的结束下标
//	//brr,存放数据的数组
//	int* brr = (int*)malloc(len * sizeof(int));//存放归并好的数据
//	int i = 0;//brr的下标
//	assert(brr != NULL);
//	//有两个归并段
//	while (low2 < len)
//	{
//		//两个归并段都有数据
//		while (low1<=high1&&low2<=high2)
//		{
//			if (arr[low1] <= arr[low2])
//			{
//				brr[i++] = arr[low1++];
//			}
//			else {
//				brr[i++] = arr[low2++];
//			}
//		}
//		//一个归并段的数据已经完成了,另外一个还有数据
//		while (low1<=high1)
//		{
//			brr[i++] = arr[low1++];
//		}
//		while (low2<=high2)
//		{
//			brr[i++] = arr[low2++];
//		}
//		//四个变量往后走,下两个归并段
//		low1 = high2 + 1;
//		high1 = low1 + gap - 1;
//		low2 = high1 + 1;
//		high2 = low2 + gap < len ? low2 + gap - 1 : len - 1;
//	}
//		//2.只有一个归并段
//		while (low1<len)//low1存在
//		{
//			brr[i++] = arr[low1++];
//		}
//		for (i = 0; i < len; i++)//将归并好的数据拷贝到arr中
//		{
//			arr[i] = brr[i];
//		}
//		free(brr);//不要忘记
//}
//void MergeSort(int*arr,int len)  //这块的时间复杂度是O(logn),
//{
//	for (int i = 1; i < len; i*=2)
//	{
//		Merge(arr, len, i);
//	}
//}
 
//基数排序(桶排序)  适用于n很大,d较小的序列  (O(d*n)(d指的是进几次出几次),O(n),稳定)
//获取十进制整数右树第figur位的数字
//static int  GetNum(int n,int figur)
//{
//	for (int i = 0; i < figur; i++)
//	{
//		n /= 10;
//
//	}
//	return n % 10;
//}
//static int  GetFigur(int* arr, int len)
//{
//	int max = arr[0];
//	for (int i = 1; i < len; i++)
//	{
//		if (max < arr[i])
//		{
//			max = arr[i];
//		}		
//	}
//	
//	int count = 0;
//	while (max != 0)
//	{
//		count++;
//		max /= 10;
//	}
//	return count;
//}
//void RadixSort(int* arr, int len)
//{
//	//需要10个链式队列,存放进队的数字
//	LinkQueue queArr[10];//定义了10个队头
//	for (int i = 0; i < 10; i++)
//	{
//		InitQueue(&queArr[i]);//初始化
//	}
//	//得到最大数字的位数,确定进队和出队的次数
//	int count = GetFigur(arr, len);
//	int index;//队列的下标
//	for (int i = 0; i < count; i++)//1.趟数2.处理每个数字从右往左的第i个数字
//	{
//		for (int j = 0; j < len; j++)//遍历数组并进队
//		{
//			index = GetNum(arr[j], i);//index保存arr[j]应该进入的队的队列下标
//			Push(&queArr[index],arr[j]);//将数字存放在对应的队列
//		}
//		//出队
//		int j = 0;
//		for(int k = 0; k < 10; k++)
//		{
//			while (!IsEmpty(&queArr[k]))
//			{
//				DeQueue(&queArr[k], &arr[j++]);
//			}
//		}
//		//销毁
//		for (int i = 0; i < 10; i++)
//		{
//			Destroy(&queArr[i]);
//		}
//	}
//}
 
 
void Show(int* arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main()
{
	int arr[] = { 4,6,8,9,2,34,56,7,12,66,99,36,87 };
	//InsertSort(arr,sizeof(arr)/sizeof(arr[0]));
	//ShellSort(arr, sizeof(arr) / sizeof(arr[0]));
	//Bubbler(arr, sizeof(arr) / sizeof(arr[0]));
	//QuickSort(arr, sizeof(arr) / sizeof(arr[0]));
	//SelectSort(arr, sizeof(arr) / sizeof(arr[0]));
	//HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	//MergeSort(arr, sizeof(arr) / sizeof(arr[0]));
	//RadixSort(arr, sizeof(arr) / sizeof(arr[0]));
	Show(arr, sizeof(arr) / sizeof(arr[0]));
	return 0;
}

1.对列头文件名命为"listqueue.h"

//这是队列的头文件
#pragma once
typedef int ElemType;
typedef struct QNode
{
	ElemType data;
	struct QNode* next;
 }QNode ,*QueuePtr;
 
typedef struct
{
	QNode* front;//队头指针
	QNode* rear;//队尾指针
}LinkQueue;//头结点的定义
 
//队列初始化
void InitQueue(LinkQueue* pq);
 
//入队
bool Push(LinkQueue* pq, ElemType val);
 
//判空
bool IsEmpty(LinkQueue* pq);
 
//获取队头元素,但不删除
bool GetHead(LinkQueue* pq, ElemType* rtval);
 
//出队,获取队头元素,且删除
bool DeQueue(LinkQueue* ps, ElemType* rtval);
 
//销毁
void Destroy(LinkQueue* ps);

2.队列函数实现名命为listqueue.cpp

//桶排序需要用到队列
//这是队列的函数实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"listqueue.h"
//队列初始化
void InitQueue(LinkQueue* pq)
{
	assert(pq != NULL);
	if (pq == NULL)
		return;
	pq->front = NULL;
	pq->rear=NULL;
 
}
 
//入队
bool Push(LinkQueue* pq, ElemType val)
{
	QNode* p = (QNode*)malloc(sizeof(QNode));
 
	assert(p != NULL);
	if (p == NULL)
		return false;
	p->data = val;
	p->next = NULL;
 
	if (!IsEmpty(pq))
	{
		pq->rear->next = p;
		pq->rear = p;
 
	}
		
	else
	{
		pq->rear = p;
		pq->front = p;
	}
	return true;
 
		
}
 
//判空
bool IsEmpty(LinkQueue* pq)
{
	return pq->front == NULL;//队头都没有元素
}
 
//获取队头元素,但不删除
bool GetHead(LinkQueue* pq, ElemType* rtval)
{
	assert(pq != NULL);
	if (pq == NULL)
		return false;
	*rtval = pq->front->data;
	return true;
}
 
//出队,获取队头元素,且删除
bool DeQueue(LinkQueue* pq, ElemType* rtval)
 
{
	assert(pq != NULL);
	if (pq == NULL)
		return false;
	*rtval = pq->front->data;
	QNode* p = (QNode*)malloc(sizeof(QNode));
	p = pq->front;
	pq->front = p->next;
	free(p);
	if (pq->front == NULL)
		pq->rear == NULL;
	return true;
 
}
//销毁
void Destroy(LinkQueue* pq)
{
	QNode* p ;
	while (pq->front!=NULL)
	{
		p = pq->front;
		pq->front = p->next;
		free(p);
	}
	pq->rear == NULL;
 
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值