#include <stdio.h>
#include <stdlib.h>
void InsertSort(int A[],int n){ //不带哨兵
int i,j;
int temp;
for(i=1;i<n;i++){ //从头到尾,依次使用固定的三步
temp = A[i]; //被检测的元素,对应L(i)
for(j=i;j>0;j--){
if(A[j-1] > temp){
A[j] = A[j-1]; //既比较大小,又往后移位
}
else{
break;
}
}
A[j] = temp; //对应第三步
}
}
void InsertSort1(int A[],int n) { //带哨兵
int i,j;
for(i=2;i<n;i++){
A[0] = A[i]; //哨兵存储
for(j=i-1;A[j]>A[0];j--){
A[j+1] = A[j];
}
A[j+1] = A[0];
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int A[5] = {2,3,1,5,99}; //不带哨兵
int B[6] = {0,2,3,1,5,99}; //带哨兵
// PrintArray(A,5);
// InsertSort(A,5);
// PrintArray(A,5);
InsertSort(B,6);
PrintArray(B,6);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void InsertSort(int A[],int n){
int i,j,low,mid,high;
for(i=2;i<n;i++){
A[0] = A[i];
low=0,high=i-1; //设置折半查找的范围
while(low<=high){
mid = (high+low)/2;
if(A[mid] >A[0]){
high = mid -1; //查找左半子表
}
else{
low = mid+1;
}
}
for(j=i-1;j>high;j--){
A[j+1] = A[j];
}
A[high+1] = A[0];
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int B[6] = {0,2,3,1,5,99}; //带哨兵
// PrintArray(A,5);
// InsertSort(A,5);
PrintArray(B,6);
InsertSort(B,6);
PrintArray(B,6);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void ShellSort(int A[],int n){
int i,j,dk;
for(dk=n/2;dk>=1;dk=dk/2){ //希尔所使用的增量序列,最后一个增量为1
for(i=dk+1;i<=n;++i){ //这个是从加了dk的地方开始,然后一个一个地加1,这样的话可以找到所有分组,各组进行直插
if(A[i]<A[i-dk]){
A[0] = A[i]; //然后在希尔的时候已经是在内部了,本身就没有这个判断,已经不需要哨兵的作用,没有起加强的效果
for(j=i-dk;j>0&&A[0]<A[j];j-=dk){ //各组进行直插
A[j+dk] = A[j]; //移动
}
A[j+dk] = A[0];
}
}
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int A[5] = {2,3,1,5,99}; //不带哨兵
int B[6] = {0,2,3,1,5,99}; //带哨兵
// PrintArray(A,5);
// InsertSort(A,5);
// PrintArray(A,5);
ShellSort(B,6);
PrintArray(B,6);
return 0;
}
void BubbleSort(int A[],int n) {
int i,j;
int temp; //用来交换
int flag; //用来判断有没有发生交换
for(i=0;i<n;i++){
flag = 0;
for(j=n-1;j>i;j--){ //这个到底是从后往前还是从前往后是有区别的,一个是将小的冒泡一个是将大的沉底,这里选择冒泡
if(A[j-1]>A[j]){ //第i次冒泡需要进行n-i次比较
temp = A[j-1]; //这儿就是移动的三次
A[j-1] = A[j];
A[j] = temp;
flag = 1;
}
}
if(flag == 0){
return;
}
}
}
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Node{
int data;
struct Node *next;
}Node,*Stack;
typedef struct LinkStack{
Node* top; //栈顶指针
int count; //元素个数
}LinkStack;
LinkStack InitStack(){
LinkStack stack;
stack.top = NULL;
stack.count = 0;
return stack;
}
void Push(LinkStack* stack,int x){
Node* s;
s = (Node*)malloc(sizeof(Node));
s->next = stack->top;
s->data = x;
stack->top = s;
stack->count++;
}
void Pop(LinkStack* stack){
Node* s;
s = stack->top;
stack->top = stack->top->next;
free(s);
stack->count--;
}
int isEmpty(LinkStack stack)
{
if (stack.count == 0)
{
return TRUE;
}
else
return FALSE;
}
int Partition(int A[],int low,int high){ //划分关键就是要找到基准最终的位置,然后划分
int pivot = A[low]; //将表中第一个元素设置为枢轴值,从而对表进行划分
while(low < high){
while (low<high&&A[high]>=pivot) { //比基准大的这一趟就不用管,下一个,我还能打!
--high;
}
A[low] = A[high]; //这个就是比基准小的,滚到左端去
while (low<high&&A[low]<=pivot) { //比基准小的这一趟就不用管,下一个
++low;
}
A[high] = A[low]; //这个就是比基准大的,滚到右端去
}
A[high] = pivot; //把基准放到它的最终位置
return high; //这个时候high与low已经相等了,无所谓返回哪个,都是k
}
void QuickSort(int A[],int low,int high){
if(low<high){
int pivotpos = Partition(A,low,high);
QuickSort(A,low,pivotpos-1);
QuickSort(A,pivotpos+1,high);
}
}
void QuickSort1(int A[],int low,int high){ //这个地方使用非递归版本
if(low>=high){
return;
}
LinkStack S = InitStack();
Push(&S,low);
Push(&S,high);
while (isEmpty(S) == 0) {
high = S.top->data;
Pop(&S);
low = S.top->data;
Pop(&S);
if(low < high){
int pivotpos = Partition(A,low,high);
//左区间
Push(&S,low);
Push(&S,pivotpos-1);
//右区间
Push(&S,pivotpos+1);
Push(&S,high);
}
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<=n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int A[] = {2, 2, 32, 12, 60, 2, 5, 72};
QuickSort(A,0,7);
PrintArray(A,7);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void SelectSort(int A[], int n){
int i,j,min;
int temp;
for(i=0;i<n-1;i++){
min = i; //记录最小元素的位置
for(j=i+1;j<n;j++){ //找到这一趟后面的最小关键字,并记录位置
if(A[j] < A[min]){
min = j;
}
if(min!=i){ //就算后面存在与现在i相同的关键字大小也无所谓,赋值后下一趟就能解决问题
temp = A[i];
A[i] = A[min];
A[min] = temp;
}
}
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int A[5] = {2,3,1,5,99};
SelectSort(A,5);
PrintArray(A,5);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void AdjustDown(int A[],int k,int n){ //这个k就是每次开始调整的点
A[0] = A[k]; //A[0]暂存
for(int i=2*k;i<=n;i*=2){ //这个循环就是为了反复调整:调整之后不是堆结构的情况
if(i<n&&A[i]<A[i+1]){
i++; //将i指向相同根下值较大的那个结点,如果这个判断错误,自然最开始的子结点大咯
}
if(A[0] >= A[i]) break; //这就不用换了
else{
A[k] = A[i];
k = i;
}
}
A[k] = A[0];
}
void AdjustUp(int A[],int k){ //这个k既是向上调整的结点,也是堆的元素个数
A[0] = A[k];
int i = k/2; //找到双亲结点
while(i>0&&A[i]<A[0]){
A[k] = A[i];
k = i;
i = k/2;
}
A[k] = A[0];
}
void BuildMaxHeap(int A[],int n){
for(int i=n;i>0;i--){
AdjustUp(A,i);
}
}
void PrintArray(int A[],int n) {
int i=1;
for(i;i<=n;i++){
printf("%d\n",A[i]);
}
}
void HeapSort(int A[],int n){
int temp;
BuildMaxHeap(A,n); //先把堆建起来!!!
for(int i=n-1;i>1;i--){ //把已经弄好的堆顶元素弄出来,交换到排序表需要的位置,完成物理变化,而不是逻辑变化
temp = A[i];
A[i] = A[1];
A[1] = temp;
AdjustDown(A,1,i-1); //交换元素以后重新建立堆结构
}
}
int main(int argc, char const *argv[]) {
int A[9] = {0,53,17,78,9,45,65,87,32};
// HeapSort(A,9);
BuildMaxHeap(A,8);
PrintArray(A,8);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void Merge(int A[],int low,int mid,int high){
int i,j,k;\
int *temp = (int *)malloc((high+1)*sizeof(int)); //temp是用来作为临时存储的辅助数组
for(k=low;k<=high;k++){
temp[k] = A[k]; //将A中所有元素都复制到辅助数组中
}
for(i=low, j=mid+1, k=i;i<=mid&&j<=high;k++){ //比较辅助数组左右两段的元素
if(temp[i] <= temp[j]){ //将辅助数组中较小值复制到A中
A[k] = temp[i++];
}
else
A[k] = temp[j++];
}
while (j<=high) { //如果第一个表没有检测完,也就是第一个表长一些,继续复制回A数组剩下的位置
A[k++] = temp[j++];
}
while (i<=mid) { //如果第二个表没有检测完,也就是第二个表长一些,继续复制回A数组剩下的位置
A[k++] = temp[i++];
}
}
void MergeSort(int A[],int low,int high){
if(low < high){
int mid = (low+high)/2;
MergeSort(A,low,mid);
MergeSort(A,mid+1,high);
Merge(A,low,mid,high);
}
}
void PrintArray(int A[],int n) {
int i=0;
for(i;i<=n;i++){
printf("%d\n",A[i]);
}
}
int main(int argc, char const *argv[]) {
int A[5] = {2,3,1,5,99};
MergeSort(A,0,4);
PrintArray(A,4);
return 0;
}
我们直接用实例理解,这里采用最低位优先
假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
箱 数
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
接着再进行一次分配,这次是根据十位数来分配:
箱 数
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。
#include<stdio.h>
#define MAX 20 //最大排序的数组元素个数
#define BASE 10
void print(int *a, int n) { //输出数组函数
int i;
for (i = 0; i < n; i++) {
printf("%d\t", a[i]);
}
}
void radixsort(int *a, int n) {
int i, b[MAX], m = a[0], exp = 1; //b数组应该是用来暂时存储的
for (i = 1; i < n; i++) {
if (a[i] > m) {
m = a[i]; //m是这个数组序列中的最大值
}
}
while (m / exp > 0) { //这个exp应该是判断的基数位置,刚开始是1,后来是10,再然后100......
int bucket[BASE] = { 0 }; //bucket用来统计0-9这些基数存在个数数组
for (i = 0; i < n; i++) {
bucket[(a[i] / exp) % BASE]++; //每个数字对应基数的数目,从高位开始
}
for (i = 1; i < BASE; i++) {
bucket[i] += bucket[i - 1]; //0-9的对应的篮子中,是包含其前面所有种类之和(包含自己)
}
for (i = n - 1; i >= 0; i--) {
b[--bucket[(a[i] / exp) % BASE]] = a[i]; //按照前面的基数排序嘛,而且我们不是统计了每个基数的个数嘛,那么轮下来,刚好能够按照大小排序,毕竟基数已经排好序了,我们按个数对应就好
}
for (i = 0; i < n; i++) {
a[i] = b[i]; //将排好序的值重新赋值回去
}
exp *= BASE;
}
}
int main() {
int arr[MAX]; //被排序的数组
int i, n;
printf("Enter total elements (n <= %d) : ", MAX);
scanf("%d", &n);
n = n < MAX ? n : MAX; //用这个来判断数组的元素个数,不超过20个,
printf("Enter %d Elements : ", n); //保存输入的数组元素
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
printf("\nARRAY : ");
print(&arr[0], n); //输出刚开始的数组刨铣
radixsort(&arr[0], n);
printf("\nSORTED : ");
print(&arr[0], n);
printf("\n");
return 0;
}
原因
败者树(当做一棵完全二叉树,所以可以用数组表示咯,可以利用这种树的性质)
将新进入选择树的结点与其父结点进行比赛:将败者存放在父结点中;而胜者再与上一级的父结点比较。
比赛沿着到根结点的路径不断进行,直到ls[1]处。把败者存放在结点ls[1]中,胜者存放在ls[0]中。
代码:
int loserTree[K]; /* 存储中间节点值,下标0处存储冠军节点 */
int leaves[K+1]; /* 从下标1开始存储叶子节点值,下标0处存储一个最小值节点 */
void adjust(int i)
{
int parent=(i+K-1)/2; /* 求出父节点的下标 */
while(parent>0)
{
if(leaves[i]>leaves[loserTree[parent]])
{
int temp=loserTree[parent];
loserTree[parent]=i;
/* i指向的是优胜者 */
i= temp;
}
parent = parent / 2;
}
loserTree[0]=i;
}
void initLoserTree()
{
int i;
for(i=1;i<K+1;i++)
scanf("%d",&leaves[i]);
leaves[0]=MIN;
for(int i=0;i<K;i++)
loserTree[i]=0;
for(int i=K;i>0;i--)
adjust(i);
}
归并路数并不是越大越好,增大路数时,相应的需要增加输入缓冲区的个数,如果可用内存空间不够,每个输入缓冲区的容量肯定要变小,那么交换数据的次数也会增大
Comments
😅 Commenting is disabled on this post.