数据结构学习笔记之排序算法

插入排序

1 直接插入排序

//直接插入排序
//1 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列
//2 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置
//3 如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面
void InsertDirectly(int *L, int len){
    int i, j, temp;
    for (i = 1; i < len; ++i){
        j = i;
        temp = L[i];    //临时变量存储待排序元素
        //寻找待插位置:只要未到数组首位或者当前元素小于待排序元素,就将当前元素后移一位
        while (j > 0 && temp < L[j-1]){
            L[j] = L[j-1];
            j--;
        }
        L[j] = temp;    //插入位置已经找到,插入
    }
}

2 折半插入排序

void InsertInHalf(int *L, int len){
    int i, j, mid;
    int low = 0, high = 0, temp = 0;
    for (i = 1; i < len; ++i){
        low = 0;
        high = i - 1;
        temp = L[i];
        //使用折半查找定诶插入位置 low
        while (low <= high){
            mid = (low + high) / 2;
            if (L[mid] > temp)
                high = mid - 1;
            else
                low = mid + 1;
        }
        //带插入位置之后的元素统一后移
        for (j = i; j > low; --j)
            L[j] = L[j-1];
        //插入元素
        L[low] = temp;
    }
}

3 希尔排序

//1 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1
//2 按增量序列个数 k,对序列进行 k 趟排序
//3 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序
//4 仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度
void HillSort(int *L, int len){
    for (int step = len / 2; step > 0; step /= 2) {
        // i : 即将插入的元素的下标,作为每一组比较数据的最后一个元素下标
        for (int i = step; i < len; ++i) {
            // j : 与 i 为同一组的元素的下标
            for (int j = i - step; j >= 0; j -= step) { //避免数组下标越界
                if (L[j] > L[j + step]){  // L[j+step] 代表即将插入的元素
                    //符合条件,插入元素
                    int temp = L[j];
                    L[j] = L[j + step];
                    L[j + step] = temp;
                }
            }
        }
    }
}

交换排序

1 冒泡排序

//1 比较相邻的元素。如果第一个比第二个大,就交换他们两个
//2 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
//3 针对所有的元素重复以上的步骤,除了最后一个
//4 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
void BubbleSort(int *L, int len){
    for (int i = 0; i < len - 1; ++i) {
        for (int j = 0; j < len - i - 1; ++j) {
            if (L[j] < L[j - 1]){
                int temp = L[j];
                L[j] = L[j + 1];
                L[j + 1] = temp;
            }
        }
    }
}

2 快速排序

//1 从数列中挑出一个元素,称为 "基准"(pivot)
//2 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面
//3 在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
//4 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序
void QuickSorted(int *L, int left, int right){
    if (left  > right)
        return;

    int temp = L[left];
    int i = left, j = right;
    while (i < j){
        while (i < j && temp <= L[j])
            j--;
	if (i < j)
	    L[i++] = L[j];
	while (i < j && temp > L[i])
	    i++;
	if (i < j)
            L[j--] = L[i];
    }
    L[i] = temp;
    QuickSorted(L, left, i - 1);
    QuickSorted(L, i + 1, right);
}

选择排序

1 简单选择排序

//1 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
//2 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾
//3 重复第二步,直到所有元素均排序完毕
void Swap(int *x, int *y){
    int temp = *x;
    *x = *y;
    *y = temp;
}

void SelectSort(int *L, int len){
    for (int i = 0; i < len - 1; ++i) {
        int min = i;
        for (int j = i + 1; j < len; ++j)   //遍历未排序的元素
            if (L[j] < L[min])  //找到目前的最小值
                min = j;    //记录最小值下标
        Swap(&L[min], &L[i]);   //交换
    }
}

2 堆排序

//1 创建一个堆 H[0……n-1]
//2 把堆首(最大值)和堆尾互换
//3 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置
//4 重复步骤 2,直到堆的尺寸为 1
void Swap(int *x, int *y){
    int temp = *x;
    *x = *y;
    *y = temp;
}

void MaxHeap(int *L, int start, int end){
    //建立父节点与子节点指标
    int dad = start;
    int son = dad * 2 + 1;
    //只有当子节点指标在范围内才进行比较
    while (son <= end){
        if (son + 1 <= end && L[son] < L[son + 1])  //选择两个子节点中最大的
            son++;
        if (L[dad] > L[son])    //父节点大于自己诶单代表调整完毕,跳出函数
            return;
        else{   //否则,交换父子内容后,再继续进行子节点和孙子结点的比较
            Swap(&L[dad], &L[son]);
            dad = son;
            son = dad * 2 + 1;
        }
    }
}

void HeapSort(int *L, int len){
    // 从最后一个父节点开始调整
    int i;
    for (i = len / 2 - 1; i >= 0; --i)
        MaxHeap(L, i, len - 1);
    //先将第一个元素和已经排序完毕的元素前一位进行交换,再重新调整,直至排序结束
    for (i = len - 1; i > 0; --i){
        Swap(&L[0], &L[i]);
        MaxHeap(L, 0, i - 1);
    }
}

3 二路归并排序

//1 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
//2 设定两个指针,最初位置分别为两个已经排序序列的起始位置
//3 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
//4 重复步骤 3 直到某一指针达到序列尾
//5 将另一序列剩下的所有元素直接复制到合并序列尾
int min(int x, int y){
    return x < y ? x : y;
}

void MergeSort(int *L, int len){
    int *a =L;
    int *b = (int *)malloc(sizeof(int) * len);
    int seg, start;
    for (seg = 1; seg < len; seg += seg){
        for (start = 0; start < len; start += seg * 2){
            int low = start;
            int mid = min(start + seg, len);
            int high = min(start + seg * 2, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;

            while (start1 < end1 && start2 < end2)
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            while (start1 < end1)
                b[k++] = a[start1++];
            while (start2 < end2)
                b[k++] = a[start2++];
        }
        int *temp = a;
        a = b;
        b = temp;
    }
    if (a != L){
        int i;
        for (i = 0; i < len; i++)
            b[i] = a[i];
        b = a;
    }
    free(b);
}

4 基数排序

#define MaxSize 100
#define Base 10

void BaseSort(int *a, int len){
    int i, b[MaxSize], m = a[0], exp = 1;

    for (i = 1; i < len; i++) {
        if (a[i] > m) {
            m = a[i];
        }
    }

    while (m / exp > 0) {
        int bucket[Base] = { 0 };

        for (i = 0; i < len; i++) {
            bucket[(a[i] / exp) % Base]++;
        }

        for (i = 1; i < Base; i++) {
            bucket[i] += bucket[i - 1];
        }

        for (i = len - 1; i >= 0; i--) {
            b[--bucket[(a[i] / exp) % Base]] = a[i];
        }

        for (i = 0; i < len; i++) {
            a[i] = b[i];
        }

        exp *= Base;
    }
}
posted @ 2021-11-01 16:37  悟道九霄  阅读(54)  评论(0编辑  收藏  举报