数据结构--排序算法

3 篇文章 0 订阅

排序算法

概述

排序算法分为内部排序和外部排序两大类。

内部排序:在计算机内存中完成的排序算法
外部排序:不能再内存中文完成,必须在磁盘或者磁带上完成的排序算法

内部排序是研究的重点问题,通常我们讲的八大排序算法也主要是讲的内部排序算法。

排序算法的稳定性和时间空间复杂度

算法介绍

本文重点介绍以下几种排序算法

1.插入算法

1.理论思想

插入排序问题的思路是将为排序元素逐一插入至已经排序的序列,从第二个元素开始插入,直至整个序列都有序终止。给定序列{49,38,65,97,76,13,27,49},从第二个元素开始插入,若遇到相等的元素则将其插入值后面

2.算法例程

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void sort_insert(int unsort[],int sort_len)
{
    int i;
    for(i=1;i<sort_len;i++)
    {
        if(unsort[i]<unsort[i-1])
        {
            int j=i;
            int temp=unsort[i];//记录当前位置     ,在已排序的序列中进行搜索

            while(j>0&&unsort[j-1]>temp)//如果j-1位置的元素小于i,则将其后移
            {
                unsort[j]=unsort[j-1];
                j--;
            }
            unsort[j]=temp;//移动完毕后,将j位置的元素置为temp
        }
    }
}
int main()
{
    int a[8]={49,38,65,97,76,13,27,49};
    sort_insert(a,8);
    printf("---------sorting-----------\n");
    for (int i=0;i<8;i++)
    {
        printf("%d\t",a[i]);
    }
    printf("\n---------End-----------\n");
    return 0;
}

3.稳定性分析

插入排序的复杂度为O(N^2)

2.选择排序

1.理论思想

选择排序的思想是每次从未排序的序列中,选择最小(最大)的数放在排序数列的后面,形成从小到大的排序思路。

给定序列{49,38,65,97,76,13,27,49}

第一趟找到最小数13,放到最前边(与首位数字交换)

交换前:| 49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 |

交换后:| 13 | 38 | 65 | 97 | 76 | 49 | 27 | 49 |

第二趟找到余下数字| 38 | 65 | 97 | 76 | 49 | 27 | 49 |里的最小数27,与当前数组的首位数字进行交换,实际没有交换,本来就在首位

交换前:| 13 | 38 | 65 | 97 | 76 | 49 | 27 | 49 |

交换后:| 13 | 27 | 65 | 97 | 76 | 49 | 38 | 49 |

第三趟继续找到剩余| 65 | 97 | 76 | 49 | 38 | 49 |数字里的最小数38,与当前数列的首位进行交换

交换前:| 13 | 27 | 65 | 97 | 76 | 49 | 38 | 49 |

交换后:| 13 | 27 | 38 | 97 | 76 | 49 | 65 | 49 |

第四趟继续找到剩余| 97 | 76 | 49 | 65 | 49 |数字里的最小数49,与当前数列的首位进行交换

交换前:| 13 | 27 | 38 | 97 | 76 | 49 | 65 | 49 |

交换后:| 13 | 27 | 38 | 49 | 76 | 97 | 65 | 49 |

第五趟从剩余的| 76 | 97 | 65 | 49 |里找到最小数49,与首位数字76交换位置

交换前:| 13 | 27 | 38 | 49 | 76 | 97 | 65 | 49 |

交换后:| 13 | 27 | 38 | 49 | 49 | 97 | 65 | 76 |

第六趟从剩余的| 97 | 65 | 76 |里找到最小数65

交换前:| 13 | 27 | 38 | 49 | 49 | 97 | 65 | 76 |

交换后:| 13 | 27 | 38 | 49 | 49 | 65 | 97 | 76 |

第七趟从剩余的| 97 | 76 |里找到最小数76
交换前:| 13 | 27 | 38 | 49 | 49 | 97 | 65 | 76 |

交换后:| 13 | 27 | 38 | 49 | 49 | 65 | 76 | 97 |

排序完毕输出正确结果| 13 | 27 | 38 | 49 | 49 | 65 | 76 | 97 |

完成一趟排序,其余步骤类似

2.算法例程

void sort_select(int unsort[],int len)
{
    int i,j,index;
    for(i=0;i<len;i++)
    {
        int unsort_min=unsort[i],index=i;
        for(j=i;j<len;j++)
        {

            if(unsort[j]<unsort_min)
            {
                unsort_min=unsort[j];
                index=j;
            }
        }
        if(index!=i)
        {
            int temp=unsort[i];
            unsort[i]=unsort[index];
            unsort[index]=temp;
        }
    }
}

3.堆排序

1.理论思想

这里的堆排序不是指堆栈,而是指的是二叉堆,是一种数据结构。二叉堆满足除了底层之外,其余的都是满的,可以分为最大堆和最小堆两种结构,最大堆的父节点一定大于其子节点,最小堆则相反。
满二叉堆可以用数组来表示,满二叉堆和数组的关系如下

堆排序的过程是每次都取出堆顶元素,后对堆进行调整,满足堆的性质。

以最大堆为例,每次取出堆顶元素,与堆的最后元素进行交换,重新调整堆,
接近于最差情况下:O(N*logN)

2.算法例程

void Adjustheap(int heap[],int i,int len);
void buildheap(int heap[],int len)
{
    for(int i=(len-1)/2;i>=0;i--)
    {
        Adjustheap(heap,i,len);
    }
}
void Adjustheap(int heap[],int i,int len)
{
    int child_left,temp;
    child_left=2*i+1;
        int min=i;
        //如果存在左儿子节点    并且左儿子节点小于母节点
        if(child_left<len&&heap[child_left]>heap[i])
        {
            min=child_left; 
        }
        //如果存在右儿子节点    并且右儿子节点小于母节点
        if(child_left+1<len&&heap[child_left+1]>heap[i])
        {
            min=child_left+1;
        }
        //如果左右儿子节点都存在的时候,且小于母节点,这个时候在儿子节点中选取最小的节点
        if(child_left+1<len&&heap[child_left+1]>heap[i]&&heap[child_left]>heap[i])
        {
            if(heap[child_left]>heap[child_left+1])
            min=child_left;
            else
                min=child_left+1;
        }
        if(min!=i)
        {
            temp=heap[i];
            heap[i]=heap[min];
            heap[min]=temp;
            Adjustheap(heap,min,len);
        }   
}
//在堆中插入一个元素
//排序
void sort_heap(int heap[],int len)
{
        buildheap(heap,len) ;//构建堆
        for(int i=len;i>0;i--)
        {
            int temp=heap[0];
            heap[0]=heap[i-1];
            heap[i-1]=temp;
            Adjustheap(heap,0,i-1);//调整母节点,只调整前几个元素 
            //将最大数放至最后一个节点
        }
}

4.冒泡排序

1.理论思想

冒泡法排序的逐次比较交换,使大的数往下沉,小数向上冒,直至完成排序,冒泡法最坏的情况下是O(N^2),最好的情况下是O(N)。算法实现简单
例子为从小到大排序,

给定序列{49,38,65,97,76,13,27,49}

第一趟排序(外循环)

第一次两两比较49 > 38交换(内循环)

交换前状态| 49 | 38 | 65 | 97 | 76 | 13 | 27 | 49 |

交换后状态| 38 | 49 | 65 | 97 | 76 | 13 | 27 | 49 |

第二次两两比较,49 < 65 不交换

第三次两两比较,65 < 97 不交换

第四次两两比较,97 > 76 交换

交换前状态| 38 | 49 | 65 | 97 | 76 | 13 | 27 | 49 |

交换后状态| 38 | 49 | 65 | 76 | 97 | 13 | 27 | 49 |

第五次两两比较,97 < 13 交换

交换前状态| 38 | 49 | 65 | 76 | 97 | 13 | 27 | 49 |

交换后状态| 38 | 49 | 65 | 76 | 13 | 97 | 27 | 49 |

依次第一次完成后
| 38 | 49 | 65 | 76 | 13 | 27 | 49 | 97 |

第二趟排序(外循环)

交换前状态| 38 | 49 | 65 | 76 | 13 | 27 | 49 | 97 |

交换后状态| 38 | 49 | 65 | 13 | 27 | 49 | 76 | 97 |

第三趟排序(外循环)

交换前状态| 38 | 49 | 65 | 76 | 13 | 27 | 49 | 97 |

交换后状态| 38 | 49 | 13 | 27 | 49 | 65 | 76 | 97 |

第四趟排序(外循环)

交换前状态| 38 | 49 | 65 | 76 | 13 | 27 | 49 | 97 |

交换后状态| 38 | 13 | 27 | 49 | 49 | 65 | 76 | 97 |

。。。。。。。。。。。。

排序完毕输出正确结果| 13 | 27 | 38 | 49 | 49 | 65 | 76 | 97 |

2.算法例程

void sort_bubble(int unsort[],int len)
{
    int i,j,temp;
    for(i=0;i<len;i++)
    {
        for(j=0;j<len-i-1;j++)
        {
            if(unsort[j]>unsort[j+1])
            {
                     temp=unsort[j];
                    unsort[j]=unsort[j+1];
                    unsort[j+1]=temp;
            }
        }
    }
}

5.快速排序

1.理论思想

在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。

给定序列{49,38,65,97,76,13,27,49}

a),先把第一项[49]取出来,

用[49]依次与其余项进行比较,

如果比[49]小就放[49]前边,38 13 27 49都比[49]小,所以全部放到[49]前边

如果比[49]大就放[49]后边,65 97 76全部放到[49]后边

一趟排完后变成下边这样:

排序前 49,38,65,97,76,13,27,49

排序后 38 13 27 49 49 65 97 76

b),对前半部分[38 13 27 49]继续进行快速排序

c) 对后半部分[65 97 76]进行快速排序

依次递归实现b)和c)

排序完毕输出正确结果| 13 | 27 | 38 | 49 | 49 | 65 | 76 | 97 |

2.算法例程

int getpart(int *heap,int begin,int end)
{

            int base=heap[begin];
            while(begin<end)
            {
                while((begin<end)&&(heap[end]>base)) end--;
                heap[begin]=heap[end];
                while((begin<end)&&(heap[begin]<=base)) begin++;
                heap[end]=heap[begin];
            }
            heap[begin]=base;
            return begin;

}

void sort_quick(int *heap,int begin,int end)
{
    if(heap==NULL||begin>=end)
        return;
    int part=getpart(heap,begin,end);
    sort_quick(heap,begin,part-1);
    sort_quick(heap,part+1,end);
}

3.复杂度分析

最好的情况下:因为每次都将序列分为两个部分(一般二分都复杂度都和logN相关),故为 O(N*logN)

最坏的情况下:基本有序时,退化为冒泡排序,几乎要比较N*N次,故为O(N*N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值