跳转至

排序

存储结构-记录序列以顺序表存储

#define MAXSIZE 20 //设记录不超过20个

typedef int KeyType; //设关键字为整型量(int型)
typedef int InfoType;

typedef struct { //定义每个记录(数据元素)的结构
    KeyType key; //关键字
    InfoType otherinfo; //其他数据项
}RedType; //Record Type

typedef struct { //定义顺序表的结构
    RedType r[MAXSIZE + 1]; //存储顺序表的向量
                            //r[0]一般作哨兵或缓冲区
    int length; //顺序表的长度
}SqList;

1-插入排序

直接插入排序

void InsertSort(SqList &L)
{
    for (int i = 2; i <= L.length; i++) { 
        L.elem[0] = L.elem[i]; //复制为哨兵
        int j = i - 1;
        for (; L.elem[0].key < L.elem[j].key; j--) { //若"<"",需将L.elem[i]插入有序字表
            L.elem[j + 1] = L.elem[j]; //记录后移
        }
        L.elem[j + 1] = L.elem[0]; //插入到正确位置
    }
    //算法时间复杂度:O(n^2),空间复杂度:O(1)
}
//插入排序
void insertion_sort(vector<int>& nums, int n) {
    for (int i = 0; i < n; ++i) {
        for (int j = i; j > 0 && nums[j] < nums[j - 1]; --j) {
            swap(nums[j], nums[j - 1]);
        }
    }
}

折半插入排序

void BInsertSort(SqList& L)
{
    for (int i = 2; i < L.length; ++i) //依次插入第2~第n个元素
    {
        L.elem[0] = L.elem[i]; //哨兵位
        int low = 1, high = i - 1; //采用二分查找法查找插入位置
            while (low <= high)
            {
                int mid = (low + high) / 2;
                if (L.elem[0].key < L.elem[mid].key)
                {
                    high = mid - 1;
                }
                else
                {
                    low = mid + 1;
                }
            } //循环结束,high+1则为插入位置
        //这个排序的根本思想,是将折半排序的比较区间,逐渐缩小到最大的小于等于哨兵元素的那个元素的位置
        //然后这个位置再加1,就是此元素应该插入的位置
        for (int j = i; j >= high + 1; --j)
        {
            L.elem[j + 1] = L.elem[j]; //移动元素
        }
        L.elem[high + 1] = L.elem[0]; //插入到正确位置
    }
}

2-交换排序

冒泡排序

void BubbleSort(SqList& L) {
    int flag = 1; //flag作为是否交换的标记
    RedType temp; //交换时临时存储
    for (int i = 1; i <= L.length - 1 && flag==1; i++) { //总共需要(L.length-1)趟
        flag = 0;
        for (int j = 1; j <= L.length - i; j++){ //第i趟需要比较(L.length-1-i)次
            if (L.elem[j].key > L.elem[j + 1].key) { //发生逆序
                flag = 1; //发生交换,flag置为1,若本趟没发生交换,flag保持为0
                temp = L.elem[j]; 
                L.elem[j] = L.elem[j + 1]; 
                L.elem[j + 1] = temp; //交换
            }
        }
    }
}
//冒泡排序
void bubble_sort(vector<int>& nums, int n) {
    bool swapped;
    for (int i = 1; i < n; ++i) {
        swapped = false;
        for (int j = 1; j < n - i + 1; ++j) {
            if (nums[j] < nums[j - 1]) {
                swap(nums[j], nums[j - 1]);
                swapped = true;
            }
        }
        if (!swapped) {
            break;
        }
    }
}

快速排序

int Partition(SqList &L, int low, int high)
{
    //设置哨兵位
    L.elem[0] = L.elem[low];
    //设置中心元素
    int pivotkey = L.elem[0].key;
    //循环排序开始
    while (low < high)
    {
        //从表尾开始找元素
        while (low < high && L.elem[high].key >= pivotkey)
            --high; //向前移动high
        //跳出上面这个循环了,意味着要么low==high了,要么在表尾找到了一个小于中心元素的元素
        L.elem[low] = L.elem[high];
        //从表头开始找元素
        while (low < high && L.elem[low].key < pivotkey)
            ++low; //向后移动low
        //跳出上面这个循环了,意味着要么low==high了,要么在表尾找到了一个大于中心元素的元素
        L.elem[high] = L.elem[low];
    } //表头low和表尾high相等时,退出循环 
    L.elem[low] = L.elem[0]; //此时low和high相同,付给谁都一样
    //返回排序后中心元素的位置
    return low; //low其实是等于high,返回low或者返回high是一个道理
}
void QSort(SqList& L, int low, int high) //对顺序表L快速排序
{
    //好像二叉树的先序遍历啊
    if (low < high) //长度大于1
    {
        //将L.elem[low...high]一分为二,privotloc为数轴元素排好序的位置
        int pivotloc = Partition(L, low, high); 
        //再对序列的左半部分进行排序找中心位置
        QSort(L, low, pivotloc - 1);
        //再对序列的右半部分进行排序找中心位置
        QSort(L, pivotloc + 1, high);
    }
}
//快速排序
//左闭右开
void quick_sort(vector<int>& nums, int l, int r) {
    //如果数组大小为1,则无需排序
    if (l + 1 >= r) {
        return;
    }
    //因为传入的是nums.size()所以要减1
    int first = l, last = r - 1, key = nums[first];
    //确定中心点位置为first
    while (first < last) {
        while (first < last && nums[last] >= key) {
            --last;
        }
        //从后往前,找到比key值小的数,搬到first的位置
        nums[first] = nums[last];
        while (first < last && nums[first] <= key) {
            ++first;
        }
        //从前往后,找到比key值大的数,搬到刚才空出来的last的位置
        nums[last] = nums[first];
    }
    //把key值赋给first位,此时的first=last
    nums[first] = key;
    //对低子表递归排序
    quick_sort(nums, l, first);
    //对高子表递归排序
    quick_sort(nums, first + 1, r);
}

3-选择排序

简单选择排序算法

void SelectSort(SqList& L) {
    RedType temp; //交换时临时存储
    for (int i = 1; i < L.length; i++) {
        int k = i;
        for (int j = i + 1; j <= L.length; j++) {
            if (L.elem[j].key < L.elem[k].key) {
                k = j; //记录最小值位置
            }
        }
        if (k != i) {
            temp = L.elem[k];
            L.elem[k] = L.elem[i];
            L.elem[k] = temp; //交换
        }
    }
}
//选择排序 
void selection_sort(vector<int>& nums, int n) {
    int mid;
    for (int i = 0; i < n - 1; ++i) {
        mid = i;
        for (int j = i + 1; j < n; ++j) {
            if (nums[j] < nums[mid]) {
                mid = j;
            }
        }
        swap(nums[mid], nums[i]);
    }
}

4-归并排序

//归并排序
void merge_sort(vector<int>& nums, int l, int r, vector<int>& temp) {
    if (l + 1 >= r) {
        return;
    }
    // divide
    int m = l + (r - l) / 2;
    merge_sort(nums, l, m, temp);
    merge_sort(nums, m, r, temp);
    // conquer
    int p = l, q = m, i = l;

    //将两个有序序列合并成一个有序序列
    while (p < m || q < r) {
        if (q >= r || (p < m && nums[p] <= nums[q])) {
            temp[i++] = nums[p++];
        }
        else {
            temp[i++] = nums[q++];
        }
    }
    for (i = l; i < r; ++i) {
        nums[i] = temp[i];
    }
}