本帖子包含的排序有:
1、库函数的qsort()排序
2、冒泡排序
3、直接插入排序
4、折半插入排序
5、2-路·插入排序
6、希尔排序
7、快速排序
8、选择排序
9、堆排序
10、归并排序
11、基数排序
12、基于链表的冒泡排序
下面将一一贴出排序的代码:
1、库函数的qsort()排序
/*
* qsort库函数排序:
* 使用qsort函数进行排序,
* 需要注意的一点就是,qsort函数的两个参数
* 相减,>= 0 的时候,数组按升序排列,< 0
* 的时候,数组按降序排列
*/
int mysort(const void* elem1, const void* elem2)
{
return *(int*)elem1 - *(int*)elem2;
}
2、冒泡排序
/*
* 冒泡排序:每一趟都将数组的第一个元素与第二个元素进行比较,
* 若为逆序,则交换两个元素的值,以此类推,每一趟
* 都把一个大的数放入到数组的后面,从而实现排序
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
void bubbleSort(int* array, int length)
{
for (int i = 0; i < length; ++i)
{
for (int j = 0; j < length - i - 1; ++j)
{
if (array[j] > array[j + 1])
{
array[j] ^= array[j + 1];
array[j + 1] ^= array[j];
array[j] ^= array[j + 1];
}
}
}
}
3、直接插入排序
/*
* 直接插入排序:是一种简单的排序方法,基本操作是将一个记录
* 插入到已排序好的有序表中,从而得到一个新的、
* 记录数增1的有序表
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
void InsertSort(int* array, int length)
{
int sentry = 0;
for (int i = 1; i < length; ++i)
{
if (array[i] < array[i - 1])
{
sentry = array[i]; //设置岗哨
array[i] = array[i - 1];
int j = 0;
for (j = i - 1; sentry < array[j]; --j) //将比岗哨小的元素往后移
array[j + 1] = array[j];
array[j + 1] = sentry; //插入到正确位置
}
}
}
4、折半插入排序
/*
* 折半插入排序:由于插入排序的基本操作是在一个有序表中进行查找和插入,这个“查找”操作可以利用“折半查找”
* 来实现,由此而来的折半插入排序
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
void BininsertSort(int* array, int length)
{
int sentry = 0, low, high, mid;
int j = 0;
for (int i = 1; i < length; ++i)
{
sentry = array[i]; //将array[i]暂存在sentry
low = 0;
high = i - 1;
while (low <= high)
{
mid = (low + high) / 2;
if (sentry > array[mid])
low = mid + 1;
else
high = mid - 1;
}
for (j = i - 1; j > high; --j) //将数据往后移动
array[j + 1] = array[j];
array[j + 1] = sentry; //插入到正确位置
}
}
5、2-路·插入排序
/*
* 2-路插入排序:该排序是在折半插入排序的基础上改进的,目的是减少排序过程中移动记录的次数,
* 但为此需要 n 个记录的辅助空间
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
void InsertSort_2(int* array, int length)
{
int first = 0, final = 0; //分别表示在辅助空间的开始和最后的位置
int* array_temp = new int[length] {0}; //创建辅助数组
int k, i;
array_temp[0] = array[0];
for (i = 1; i < length; ++i)
{
if (array[i] < array_temp[first]) //小于最小元素
{
first = (first - 1 + length) % length;
array_temp[first] = array[i];
}
else if (array[i] > array_temp[final]) //大于最大元素
{
final = (final + 1 + length) % length;
array_temp[final] = array[i];
}
else //折半查找
{
k = (final + 1 + length) % length;
while (array_temp[((k - 1) + length) % length] > array[i])
{
array_temp[(k + length) % length] = array_temp[(k - 1 + length) % length];
k = (k - 1 + length) % length;
}
array_temp[(k + length) % length] = array[i];
final = (final + 1 + length) % length;
}
}
for (k = 0; k < length; ++k) //拷贝数组
array[k] = array_temp[(first + k) % length];
delete[] array_temp; //释放辅助空间
}
6、希尔排序
/*
* 希尔(Shell)排序:又称“缩小增量排序”,基本思想是:先将整个待排记录序列分割成若干子序列,
* 分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录
* 进行一次直接插入排序
* 时间复杂度:O(nlog2n)
* 稳定性:不稳定
*/
void ShellSort(int* array, int length)
{
int interval = 1; //初始化一个间隔
while (interval < length / 3) //设置最大间隔
interval = interval * 3 + 1;
while (interval > 0) //进行插入排序
{
long tmp = 0;
for (int i = interval; i < length; ++i)
{
tmp = array[i];
int j = i;
while (j > interval - 1 && array[j - interval] >= tmp)
{
array[j] = array[j - interval];
j -= interval;
}
array[j] = tmp;
}
interval = (interval - 1) / 3; //缩小间隔
}
}
7、快速排序
/*
* 快速排序(快排):是对冒泡排序的一种改进,它的基本思想是:通过一趟排序将待排序的记录
* 分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小
* ,则可以分别对这两部分记录继续进行排序,以达到整个序列有序
* 时间复杂度:O(nlog2n)--->当数组基本有序时,退化接近冒泡排序,时间复杂度为O(n^2)
* 稳定性:不稳定
*/
int Partition(int* arr, int low, int high)//首先需要一个函数返回轴驱的位置 这是每一排序的基础
{
/*交换数组当中的值 使轴驱记录到自己该指定的位置 并返回其所在的位置 此时 轴驱前(后)的数值均不
大(小)于轴驱位置上的数值*/
int pivotkey = arr[low];
while (low < high)
{
while (low < high && arr[high] >= pivotkey)
--high;
arr[low] = arr[high];
while (low < high && arr[low] <= pivotkey)
++low;
arr[high] = arr[low];
}
arr[low] = pivotkey;
return low;
}
void QuickSort(int* arr, int low, int high) //注意,high应为数组最大个数减一
{
/*利用上面函数返回值进行数组排序 快速排序*/
if (low < high)
{
int value = Partition(arr, low, high);
QuickSort(arr, low, value - 1);
QuickSort(arr, value + 1, high);
}
}
8、选择排序
/*
* 选择排序:每次选择最小的数值,并且把最小数值赋给排序数组的前端,依次进行,直到数组有序
* 时间复杂度:O(n^2)
* 稳定性:不稳定
*/
void SelectSort(int* array, int length)
{
int i, j, min = 0, temp = 0;
for (i = 0; i < length - 1; ++i)
{
min = i; //查找最小值
for (j = i + 1; j < length; ++j)
{
if (array[min] > array[j])
min = j;
}
if (min != i)
{
//交换数值
array[min] ^= array[i];
array[i] ^= array[min];
array[min] ^= array[i];
}
}
}
9、堆排序
/*
* 堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,堆是
* 具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
* 或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
* 时间复杂度:O(nlog2n)
* 稳定性:不稳定
*/
void max_heapify(int* arr, int start, int end) {
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end)
{ //若子节点指标在范围内才做比较
if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的
son++;
if (arr[dad] > arr[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
return;
else
{ //否则交换父子内容再继续子节点和孙节点比较
arr[dad] ^= arr[son];
arr[son] ^= arr[dad];
arr[dad] ^= arr[son];
dad = son;
son = dad * 2 + 1;
}
}
}
void heapsort(int* arr, int len)
{
//初始化,i从最後一个父节点开始调整
for (int i = len / 2 - 1; i >= 0; i--)
max_heapify(arr, i, len - 1);
//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕
for (int i = len - 1; i > 0; i--)
{
arr[0] ^= arr[i];
arr[i] ^= arr[0];
arr[0] ^= arr[i];
max_heapify(arr, 0, i - 1);
}
}
10、归并排序
/*
* 归并排序:(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)
* 的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序
* 时间复杂度:O(nlog2n)
* 稳定性:稳定
*/
void _merge_inArray(int* array, int left, int mid, int right) //用来合并分开的数组
{
int length = right - left + 1; //定义一个辅助空间的长度
int* ptemp = new int[length] {0};//分配一个辅助数组
//合并操作
int low = left;//左边区间起始下标
int high = mid + 1;//右边区间起始下标
int index = 0;//辅助数组的下标
while (high <= right) //右区间没有合并完
{
while (low <= mid && array[low] <= array[high])//证明左区间没有合并完,且左区间的值小于右区间的值
ptemp[index++] = array[low++]; //把左边的值放进辅助数组 low++表示左边往高位移,
//下一次需要判断左边的新下标,index++表示下一次放进辅助数组的新下标
if (low > mid)//证明左区间已经放完
break;
while (high <= right && array[low] > array[high])
ptemp[index++] = array[high++];
}
//到这一步证明有一个区间已经合并完成
if (high <= right)//证明右边没有完成
memmove(&ptemp[index], &array[high], sizeof(int) * (right - high + 1));
if (low <= mid)//证明左边没有完成
memmove(&ptemp[index], &array[low], sizeof(int) * (mid - low + 1));
//把所有区间都合并到辅助区间
memmove(&array[left], ptemp, sizeof(int) * length);
delete[] ptemp;
}
void _merge(int* array, int left, int right)//将数组拆分成两个左右区间
{
if (left >= right) //递归终止操作,左右相等说明就只有一个元素,就不需要分了
return;
int mid = ((right - left) >> 1) + left; //求中点
_merge(array, left, mid);//拆分左
_merge(array, mid + 1, right);//拆分右
//并操作
_merge_inArray(array, left, mid, right);
}
void MergeSort(int* array, int length)
{
_merge(array, 0, length - 1);
}
11、基数排序
/*
* 基数排序:(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)
* 或bin sort,顾名思义,它是透过键值的部份资讯
* ,将要排序的元素分配至某些“桶”中,藉以达
* 到排序的作用
* 时间复杂度:O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
* 稳定性:稳定
*/
int maxbit(int* data, int n) //辅助函数,求数据的最大位数
{
int d = 1; //保存最大的位数
int p = 10;
for (int i = 0; i < n; ++i)
{
while (data[i] >= p)
{
p *= 10;
++d;
}
}
return d;
}
void radixsort(int* array, int length) //基数排序
{
int d = maxbit(array, length);
int* tmp = new int[length];
int* count = new int[10]; //计数器
int i, j, k;
int radix = 1;
for (i = 1; i <= d; i++) //进行d次排序
{
for (j = 0; j < 10; j++)
count[j] = 0; //每次分配前清空计数器
for (j = 0; j < length; j++)
{
k = (array[j] / radix) % 10; //统计每个桶中的记录数
count[k]++;
}
for (j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
for (j = length - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
{
k = (array[j] / radix) % 10;
tmp[count[k] - 1] = array[j];
count[k]--;
}
for (j = 0; j < length; j++) //将临时数组的内容复制到data中
array[j] = tmp[j];
radix = radix * 10;
}
delete[]tmp;
delete[]count;
}
12、基于链表的冒泡排序
/*
* 使用冒泡排序思想对链表进行排序操作
*/
struct arr //链表的节点数据
{
int data;
arr* next;
};
arr* moveto(const arr node, int n) //将链表指针移动到指定位置,并返回
{
arr* p = node.next;
if (p)
{
for (int i = 0; i < n; ++i)
{
p = p->next;
}
}
return p;
}
int count_list(arr node) //获得链表长度
{
int count = 0;
arr* p = node.next;
while (p)
{
count++;
p = p->next;
}
return count;
}
void create_list(arr* node, int length) //创建一个链表
{
arr* p = node;
arr* temp = NULL;
for (int i = 0; i < length; ++i)
{
temp = new arr;
temp->data = rand() % length;
temp->next = NULL;
p->next = temp;
p = p->next;
}
}
void show_list(const arr node) //显示链表数据
{
arr* p = node.next;
while (p)
{
std::cout << p->data << " ";
p = p->next;
}
std::cout << std::endl;
}
void destroy_list(arr* node) //销毁链表
{
arr* p = node;
arr* temp = nullptr;
while (p->next)
{
temp = p->next;
p->next = temp->next;
free(temp);
}
}
void list_sort(arr* node) //链表排序
{
int count = count_list(*node);
arr* p = nullptr;
for (int i = 0; i < count - 1; ++i)
{
for (int j = 0; j < count - 1 - i; ++j)
{
p = moveto(*node, j);
if (p)
{
if (p->data > p->next->data)
{
p->data ^= p->next->data;
p->next->data ^= p->data;
p->data ^= p->next->data;
}
}
}
}
}
使用的main函数
int main()
{
int array[13] = { 56, 95, 45, 21, 48, 75, 23, 11, 99, 33, 22, 44, 88 };
//qsort(array,10,sizeof(int),mysort);
//InsertSort(array, 13);
//BininsertSort(array, 13);
//InsertSort_2(array, 13);
//ShellSort(array, 13);
//QuickSort(array, 0, 12);
//SelectSort(array, 13);
//MergeSort(array, 13);
//heapsort(array, 13);
//radixsort(array, 13);
arr head; //建立链表头节点
create_list(&head, 13); //创建链表
list_sort(&head); //排序链表
show_list(head); //显示链表
for (int i = 0; i < 13; ++i)
std::cout << array[i] << " ";
return 0;
}