数据结构八大排序

1冒泡排序

思路:把大数依次放在数组后面,最后实现排序,每次交换都是把大数放在数组后面

优点:稳定

确定:慢,每次只移动相邻两个元素

时间复杂度:最好O(n),最坏(数组反序)O(n2)。平均O(n2)

public static void Sort(int[] array)

    {

        for (int i = 0; i < array.Length; i++)

        {

            for (int j = 0; j < array.Length - 1 - i; j++)

            {

                if (array[j] > array[j + 1])

                {

                    int temp = array[j + 1];

                    array[j + 1] = array[j];

                    array[j] = temp;

                }

            }

        }

    }

2快速排序

分治思想:先保证前半部分都小于后半部分,然后分别对前半部分和后半部分排序。

优点:高效极快,数据移动少

缺点:不稳定

时间复杂度:最坏O(n2)。平均O(nlogn)。

    public static void QuickSort(int[] array, int left, int right)

    {

        if (left < right)

        {

            //取中间元素作为基准,小于的左移 大于的右移

            int middle = array[(left + right) / 2];

            int i = left - 1;

            int j = right + 1;

            while (true)

            {

                //移动下标 左边的右移 右边的左移

                while (array[++i] < middle && i < right) ;

                while (array[--j] > middle && j >0);

                if (i > j) break;

                //交换位置

                int temp = array[i];

                array[i] = array[j];

                array[j] = temp;

            }

            QuickSort(array, left, i - 1);

            QuickSort(array, j + 1, right);

        }

    }

3插入排序

思想:从索引1开始遍历,不断与前一个数进行比较,如果前一个数比自己大则换位置

优点:稳定,快

缺点:比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候,但用链表可以解决这一问题。

时间复杂度:O(n2)

    public static void InsertSort(int[] array)

    {

        //将带比较的数值与它的前一数值进行比较,所以外层循环从第二个数值开始

        for (int i = 0; i < array.Length; i++)

        {

            //如果当前元素小于其前面的元素

            if (array[i] < array[i - 1])

            {

                //一趟完成时 将带比较数值置入比他小的数值的后一位

                int temp = array[i];

                int j = 0;

                for (j = i - 1;j>=0&& temp < array[j]; j--)

                {

                    array[j + 1] = array[j];

                }

                array[j+1] = temp;

            }

        }

    }

4希尔排序

    public  static void ShellSort(int[] array){
        int length = array.Length;
        for (int h = length / 2; h > 0; h = h / 2) {
            //hear is insert sort
            for(int i = h;i<length;i++){
                int temp = array [i];
                if (temp < array [i - h]) {
                    for (int j = 0; j < i; j += h) {
                        if (temp < array [j]) {
                            temp = array [j];
                            array [j] = array [i];
                            array [i] = temp;
                        }
                    }
                }
            }
        }
    } 

5选择排序
进行比较操作的时间复杂度为O(n^2),进行移动操作的时间复杂度为O(n)。

    public static void SimpleSelectSort(int[] array){
        int temp = 0;
        int min = 0;//最小数标记
        for (int i = 0 ;i<array.Length;i++){
            min = i;
            for (int j = i + 1; j < array.Length; j++) {
                if (array [temp] > array [j]) {
                    min = j;
                }
            }
            temp = array [i];
            array [i] = array [min];
            array [min] = temp;
        }
    }

6堆排序选择排序

利用数组特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

//堆排序
    public static void HeapSort(this int[] array,int top){
        List<int> topNode = new List<int> ();
        for (int i = array.Length / 2 - 1; i >= 0; i--) {
            HeapAdjust (array, i, array.Length);
        }
        for (int i = array.Length - 1; i >= array.Length - top; i--) {
            int temp = array [0];
            array [0] = array [i];
            array [i] = temp;
            HeapAdjust (array, 0, i);
        }
    }
    //构建堆
    private static void HeapAdjust(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])
                break;
            array [parent] = array [child];
            parent = child;
            child = 2 * parent + 1;
        }
        array [parent] = temp;
    }

 

7归并排序

分治法:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。
如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;

归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

    //归并排序
    public static void MergeSort(this int[] array,int frist,int last){
        if (frist < last) {
            int middle = (frist + last) / 2;
            MergeSort (array, frist, middle);
            MergeSort (array, middle, last);
            Merger (array, frist, middle, last);
        }
    }
    public static void Merger(int[] array,int frist,int middle,int last){
        Queue<int> tempV = new Queue<int> ();
        int indexA, indexB;
        //设置indexA 并扫描subArray1[frist,middle]
        //设置indexB 并扫描subArray1[middle,last]
        indexA = frist;
        indexB = middle;
        //在灭有比较完两个子标的情况下,比较v[indexA]和v[indexB]
        //将其中小的放到临时变量tempV中
        while(indexA<middle&&indexB <last){
            if (array [indexA] < array [indexB]) {
                tempV.Enqueue (array [indexA]);
                indexA++;
            } else {
                tempV.Enqueue (array [indexB]);
                indexB++;
            }
        }
        //复制没有比较完字表中的元素
        while(indexA<indexB){
            tempV.Enqueue (array [indexA]);
            indexA++;
        }
        while(indexA<last){
            tempV.Enqueue (array [indexB]);
            indexB++;
        }
        int index = 0;
        while (tempV.Count > 0) {
            array [frist + index] = tempV.Dequeue ();
            index++;
        }
    }

 

 

8基数排序

时间复杂度O (nlog(r)m),r为所采取的基数,m为堆数

    // 基数排序 约定:待排数字中没有0,如果某桶内数字为0则表示该桶未被使用,输出时跳过即可
    // 待排数组 桶数组第一维长度 桶属猪第二维长度
    public static void RadixSort(this  int[] array,int array_x=10,int array_y = 100){
        //最大数字不超过999999999...(array_x个9)
        for(int i =0;i<array_x;i++){
            int[,] bucket = new int[array_x, array_y];
            foreach (var item in array) {
                int temp = (item / (int)Math.Pow (10, i)) % 10;
                for (int m = 0; m < array_y; m++) {
                    if (bucket [temp, m] == 0) {
                        bucket [temp, i] = item;
                        break;
                    }
                }
            }
            for (int n = 0, x = 0; x < array_x; x++) {
                for (int y = 0; y < array_y; y++) {
                    if (bucket [x, y] == 0)
                        continue;
                    array [n++] = bucket [x,y];
                }
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/dongjingxia/article/details/86491605