IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 十大排序算法 -> 正文阅读

[数据结构与算法]十大排序算法

十大排序

排序方法有十种,分别是:一、冒泡排序;二、选择排序;三、堆排序;四、插入排序;五、希尔排序;六、归并排序;七、快速排序;八、计数排序;九、桶排序;十、基数排序。

O(n)都是理想情况,不用排序

一、冒泡排序

直接上代码。

//找到当前最大的数不断向后冒泡,直至最后一个最小的数

void bubbleSort(int a[],int len) 
{
    for(int i = 0; i<len; ++i)
      //排在最后的数已比较过是最大的,不用再比较
        for(int  j = 0;  j < len-i-1; ++j)     
            if(a[j] > a[j+1]) 	 //升序
            		swap(a[j],a[j+1]); 	 //c++交换两个数
}

模拟一下:
5 3 7 9 6 2 8
3 5 7 6 2 8 9
3 5 6 2 7 8 9
3 5 2 6 7 8 9
3 2 5 6 7 8 9
2 3 5 6 7 8 9
时间复杂度O(n)~O(n2

二、选择排序

直接上代码。

//选择当前最小的数,将其排在当前对应的最小数的位置即可

void selectionSort(int a[], int len)
 {
     for  (int  i = 0; i < len - 1; ++i)
      {
         int minpos = i, temp = i;
         for  ( int j = i + 1; j < len; ++j) 
             if  (a[j] < a[minpos])     		//寻找最小的数
                 minpos = j;                    //将最小数的索引保存
		 swap(a[temp],a[minpos]);
     }
}

模拟一下:
5 3 7 9 6 2 8
2 3 7 9 6 5 8
2 3 7 9 6 5 8
2 3 5 9 6 7 8
2 3 5 6 9 7 8
2 3 5 6 7 9 8
2 3 5 6 7 8 9
时间复杂度O(n)~O(n2

三、堆排序

直接上代码。

//堆排序,近似二叉树的一种处理方法。
//大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
//小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列。

//构建大顶堆
void heapmax(int a[], int i, int len)
{
	// 调整i位置的结点
	// 先保存当前结点的下标
	int max = i;
	int lchild = i * 2 + 1;  	//左节点
	int rchild = i * 2 + 2;		//右节点
	if (lchild < len && a[lchild] > a[max])  max = lchild;
	if (rchild < len && a[rchild] > a[max])  max = rchild;
	// 若i处的值比其左右孩子结点的值小,就将其和最大值进行交换
	if (max != i)
	{
		swap(a[max],a[i]);
		heapmax(a, max, len);
	}
}
 
// 堆排序
void heapSort(int a[], int len)
{
	// 初始化堆
	// len / 2 - 1是二叉树中最后一个非叶子结点的序号
	for (int i = len / 2 - 1; i >= 0; --i)
	{
		heapmax(a, i, len);
	}
	// 交换堆顶元素和最后一个元素
	for (int i = len - 1; i >= 0; --i)
	{
		swap(a[0],a[i]);
		heapmax(a, 0, i);
	}
}

具体如图:
大顶堆的构建时间复杂度:O(nlogn)。

四、插入排序

直接上代码。

//将当前数与前面的数进行比较,如果小,就插入


void insertionSort(int a[],int len)
 {
     for  (int i = 1; i < len; ++i) 
     {
         int pos = i - 1;   	//标记位置
         int temp = a[i];		//记录当前数
         
         while (pos >= 0 && a[pos] > temp)  //找到插入的位置
          {
             arr[pos + 1] = arr[pos];       //将大的数向后移,但又不超过当前位置
             --pos;                         //pos -= 1;
         }
         if(pos + 1 != i)
         	arr[pos + 1] = current;
     }
     return  arr;
}

模拟一下:
5 3 7 9 6 2 8
3 5 7 9 6 2 8
3 5 7 9 6 2 8
3 5 7 9 6 2 8
3 5 6 7 9 2 8
2 3 5 6 7 9 8
2 3 5 6 7 8 9
时间复杂度O(n)~O(n2

五、希尔排序

直接上代码。

//希尔排序建立在直接插入排序的基础上:直接插入排序 d=1,shell 排序 d=x;
//将直接排序分组进行;

//d:初始增量(分组数)
void shellSort(int a[], int len, int d)
{
    for(int inc = d; inc > 0; inc /= 2)   //d=1,相当于直接插入排序  
    {   
        for(int i = inc; i < len; ++i)
        {  
            int pos = i - inc;
            int temp = a[i];
            while(pos >= 0 && a[pos] > temp)   //对应直接插入排序,1 == inc
            {
                a[pos+inc] = a[pos];
                pos -= inc;
            }
            if((pos + inc) != i)		
                a[pos + inc] = temp;	
        }
    }
}

模拟一下:
d=4;如图:
shell排序时间复杂度: O(n)~O(n2),

六、归并排序(二路归并排序)

直接上代码。

// 两两归并比较大小,再两两合并比较大小交换,最后合在一起排序。
void mergeSort(int a[], int start, int end, int *temp)
{
	if (start >= end) return ; //收尾相等,归并完毕
	int mid = (start + end) / 2;
	mergeSort(a, start, mid, temp);
	mergeSort(a, mid + 1, end, temp);

	// 合并两个有序序列
	int len = 0; // 表示辅助空间有多少个元素
	int i_start = start;
	int i_end = mid;
	int j_start = mid + 1;
	int j_end = end;
	while (i_start <= i_end && j_start <= j_end)
	{
		if (a[i_start] < a[j_start])    temp[len++] = a[i_start++];
		else    temp[len++] = a[j_start++];
	}
	while (i_start <= i_end)    temp[len++] = a[i_start++];
	while (j_start <= j_end)    temp[len++] = a[j_start++];
	//把辅助空间的数据放到原空间
	for (int i = 0; i < len; i++)   a[start + i] = temp[i];
}

借用图片归并排序
时间复杂度:O(nlogn)

七、快速排序

//建立在冒泡排序的基础上
//不断向两边扫并设定指定的值,将小、大的放在key的两边。

void quickSort(int a[],int l, int r)
{
    if(l >= r)  return;
    int left = l, right = r;
    int key = a[left];    /*用数组的第一个记录作为分区元素*/
    while(left != right)
    {
        /*从右向左扫描,找第一个码值小于key的记录,并交换到key*/
        while(left < right && a[right] >= key)   --right;
        a[left] = a[right];
        
        /*从左向右扫描,找第一个码值大于key的记录,并交换到右边*/
        while(left < right && a[left] <= key) 	 ++left;
        a[right] = a[left];    
    }
    a[left] = key;    /*分区元素放到正确位置*/
    quickSort(a,l,left-1);
    quickSort(a,left+1,r);
}

时间复杂度:O(nlogn)~O(n2)

八、计数排序

直接上代码:

//标记,输出,快,有局限性

#define MAXNUM 20    //待排序数的最大个数
#define MAX    100   //待排序数的最大值
int count[MAXNUM] = {0};
int ans[MAXNUM] = {0};
void countSort(int a[], int count[], int n)  
{   
    //统计i的次数   
    for(int i = 0; i < n; ++i)    ++count[ a[i] ];  
    
    //对所有的计数累加,作用是统计a数组值和小于a数组值出现的个数
    for(int i = 1; i <= MAX; ++i)   count[i] += count[i - 1];   
    
    //逆向遍历源数组(保证稳定性),根据计数数组中对应的值填充到新的数组中   
    for(i = n - 1; i >= 0; --i)  
        ans[ --count[ a[i] ] ] = a[i];  
}

时间复杂度:O(n+k)

九、桶排序

直接上代码:

//分类,将一段内的数,放在“桶”内,进行桶内部排序,组合桶。
//代码仅供参考
typedef struct node
 { 
     int keyNum;	//桶中数的数量
     int key;   	//存储的元素
     struct node *next;  
 }KeyNode;    

 //keys待排序数组,size数组长度,bucket_size桶的数量
 void incSort(int keys[],int size,int bucket_size)
 { 
     KeyNode* k=(KeyNode *)malloc(sizeof(KeyNode)); //用于控制打印
     int i,j,b;
     KeyNode **bucket_table=(KeyNode **)malloc(bucket_size*sizeof(KeyNode *)); 
     for(i = 0; i<bucket_size; i++)
     {  
         bucket_table[i] = (KeyNode *)malloc(sizeof(KeyNode)); 
         bucket_table[i]->keyNum = 0;//记录当前桶中是否有数据
         bucket_table[i]->key = 0;   //记录当前桶中的数据  
         bucket_table[i]->next = NULL; 
     }    

     for(j=0;j<size;j++)
     {   
         int index;
         KeyNode *p;
         KeyNode *node = (KeyNode *)malloc(sizeof(KeyNode));   
         node->key = keys[j];  
         node->next = NULL;  

         index = keys[j]/10;        //映射函数计算桶号  
         p = bucket_table[index];   //初始化P成为桶中数据链表的头指针  
         if(p->keyNum == 0)//该桶中还没有数据 
         {    
             bucket_table[index]->next = node;   
              //桶的头结点记录桶内元素各数,此处加一 
             ++(bucket_table[index]->keyNum); 
         }
         else	//该桶中已有数据 
         {   
             //链表结构的插入排序 
             while(p->next != NULL && p->next->key <= node->key)   
                 p = p->next;    
             node->next = p->next;     
             p->next = node;      
             ++(bucket_table[index]->keyNum);   
         }
     }
     //打印结果
     for(b=0; b < bucket_size; b++)   
         //判断条件是跳过桶的头结点,桶的下个节点为元素节点不为空
         for(k=bucket_table[b]; k->next != NULL; k = k->next)  
         {
             printf("%d ",k->next->key);
         }
 }  

时间复杂度:O(n+k) k为桶内排序所需时间。

十、基数排序

按位(个十百千万…)对应的数,分类,计数,从高位开始,依次比较,高位相同,降位,到最后即可,
图解:
以【520 350 72 383 15 442 352 86 158 352】序列为例,排序过程描述如下:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
代码:

//代码仅供参考
/******************************************************** 
*函数名称:GetDigitInPos 
*参数说明:num 一个整形数据 
*        pos 表示要获得的整形的第pos位数据 
*说明:   找到num的从低到高的第pos位的数据 
*********************************************************/  
inline int GetDigitInPos(int num,int pos)  
{  
    int temp = 1;  
    for (int i = 0; i < pos - 1; i++)  
        temp *= 10;  
    return (num / temp) % 10;  
}

/******************************************************** 
*函数名称:RadixSort 
*参数说明:unorderArray无序数组; 
*        dataNum无序数据个数 
*说明:   基数排序 
*时间复杂度:O(dn),d无序数最大位数,n无序数个数
*********************************************************/  
#define RADIX 10    //整形排序,基数为10,需要十个桶  
#define KEYNUM 10   //关键字位数,这里为整形位数  
inline void RadixSort(int* unorderArray, int dataNum)  
{  
    int *radixArrays[RADIX];    //分别为0~9基数的存放空间  
    for (int i=0; i<10; i++)  
    {  
        radixArrays[i] = (int *)malloc(sizeof(int)*(dataNum + 1));  
        radixArrays[i][0] = 0;    //index为0处记录这组数据的个数  
    }  
    for (int pos=1; pos<=KEYNUM; pos++)   //从个位开始入桶并出桶
    {   
        for (int i=0; i<dataNum; i++)    //分配过程  
        {  
            int num = GetDigitInPos(unorderArray[i],pos);  
            int index = ++radixArrays[num][0];  
            radixArrays[num][index] = unorderArray[i];  
        }  
        for (int i=0, j=0; i<RADIX; i++)//收集  
        {  
            for (int k = 1; k <= radixArrays[i][0]; k++)  
                unorderArray[j++] = radixArrays[i][k];  
            radixArrays[i][0] = 0;    //出桶完毕,复位  
        }  
    }  
}  

时间复杂度:O(k*n) k最多位数的位数。

资源参考:
链接一: https://blog.csdn.net/a20180825/article/details/76608531
链接二: https://blog.csdn.net/liang_gu/article/details/80627548
链接三: https://blog.csdn.net/k346k346/article/details/45576137

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:09:52  更:2022-07-20 19:12:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:17:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码