第九章 排序【数据结构】【精致版】

news2024/11/28 23:05:12

第九章 排序【数据结构】【精致版】

  • 前言
  • 版权
  • 第九章 排序
    • 9.1 概述
    • 9.2 插入类排序
      • 9.2.1 直接插入排序
        • **1-直接插入排序.c**
      • 9.2.2 折半插入排序
        • **2-折半插入排序.c**
      • 9.2.3 希尔排序
    • 9.3 交换类排序
      • 9.3.1冒泡排序
        • **4-冒泡排序.c**
      • 9.3.2 快速排序
        • **5-快速排序.c**
    • 9.4 选择类排序
      • 9.4.1 简单选择排序
        • **6-简单选择排序.c**
      • 9.4.2 树形选择排序
      • 9.4.3 堆排序
        • **7-堆排序.c**
    • 9.5 归并类排序
      • 9.5.1 二路归并排序
        • **8- 二路归并排序.c**
      • 9.5.2自然归并排序
        • **9-自然归并排序.c**
    • 9.6 分配类排序
      • 9.6.1 多关键字排序
        • **10-多关键字排序.c**
      • 9.6.2 链式基数排序
        • **11-链式基数排序.c**
    • 9.7 外部排序
      • 9.7.1置换选择排序
      • 9.7.2多路归并外排序
    • 9.8 算法总结
  • 最后

前言

2023-11-7 16:23:34
以下内容源自《【数据结构】【精致版】》
仅供学习交流使用

版权

禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话

第九章 排序

9.1 概述

记录序列的数据类型描述如下

#define MAXSIZE 1000  //假设的文件长度,即待排序的记录数目  
typedef int KeyType;  //假设的关键字类型
typedef int OtherType;
typedef struct{
	KeyType key;//关键字项
	OtherType other_data;//其他数据项,类型OtherType依赖于具体应用而定义  
}RecordType; //记录类型
typedef struct{
	RecordType r[ MAXSIZE+1];
	int length;//序列长度,即记录个数
}RecordList; //记录序列类型,即顺序表类型


RecordList create(int nums[],int n){
	RecordList L;
	L.length=n;
	for(int i=1;i<=n;i++){
		RecordType t={nums[i],0};
		L.r[i]=t;
	}
	return L;
}

void print(RecordList L){
	int n=L.length;
	for(int i=1;i<=n;i++){
		printf("%d ",L.r[i].key);
	}
	printf("\n");
}

9.2 插入类排序

9.2.1 直接插入排序

1-直接插入排序.c
#include <stdio.h>
#include "0-RecordList.h"

// 【算法9-1】直接插入排序
RecordList insertSort(RecordList L){
    for (int i = 2; i <= L.length; i++){
        L.r[0] = L.r[i]; // 监视哨备份待查记录
        int j;
        for (j = i - 1; L.r[0].key < L.r[j].key; j--){
            L.r[j + 1] = L.r[j]; // 记录后移
        }
        L.r[j + 1] = L.r[0]; // 插入正确位置
    }
  	return L;
}

// 待插记录已是当前有序的最大记录,不需要后移排序
// 【算法9-2】改进的直接插入排序
RecordList insertSortPlus(RecordList L){
    for (int i = 2; i <= L.length; i++){
        if (L.r[i].key < L.r[i - 1].key){      // 如果不小于,就是待插记录已是当前有序的最大记录
            L.r[0] = L.r[i]; // 监视哨备份待查记录
            int j;
            for (j = i - 1; L.r[0].key < L.r[j].key; j--){
                L.r[j + 1] = L.r[j]; // 记录后移
            }
            L.r[j + 1] = L.r[0]; // 插入正确位置
        }
    }
    return L;
}



int main(){
    int n=8;
    int nums[9]={-1,33,12,25,46,33,68,19,80};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//33 12 25 46 33 68 19 80
    
    print(insertSort(L)); //12 19 25 33 33 46 68 80  
    print(insertSortPlus(L)); //12 19 25 33 33 46 68 80

}

9.2.2 折半插入排序

2-折半插入排序.c
#include <stdio.h>
#include "0-RecordList.h"


//【算法9-3】折半插入排序
//因为插入到有序列中,有折半快速找到位置
RecordList biInsertSort(RecordList L){
    for (int i = 2; i <=L.length ; i++) {
        if(L.r[i].key<L.r[i-1].key){//如果不小于,就是待插记录已是当前有序的最大记录
            L.r[0]=L.r[i];//监视哨备份待查记录
            //折半查找nums[i]插入位置
            int low=1;
            int high=i-1;
            while (low<high){
                int mid=(low+high)/2;
                if(L.r[0].key<L.r[mid].key){
                    high=mid-1;
                }else{
                    low=mid+1;
                }
            }
            for (int j = i-1; j>=low; j--) {
                L.r[j+1]=L.r[j];//记录后移
            }
            L.r[low]=L.r[0];//插入正确位置
    	}
    }
    return L; 
}


int main(){
    int n=8;
    int nums[9]={-1,33,12,25,46,33,68,19,80};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//33 12 25 46 33 68 19 80
    
    print(biInsertSort(L)); //12 19 25 33 33 46 68 80   

}

9.2.3 希尔排序

#include <stdio.h>
#include "0-RecordList.h"


#include <stdio.h>
#include "0-RecordList.h"


//【算法9-4】希尔排序
//最小增量排序
void shellInsert(RecordList* L,int dk){
    for (int i = dk+1; i<=L->length ; i++) {
        if(L->r[i].key<L->r[i-1].key){//如果不小于,就是待插记录已是当前有序的最大记录
            L->r[0]=L->r[i];//监视哨备份待查记录
            int j;
            for (j = i-dk; j>0&&L->r[0].key<L->r[j].key; j-=dk) {
                L->r[j+dk]=L->r[j];//记录后移
            }
            L->r[j+dk]=L->r[0];//插入正确位置
        }
    }
}
//dlta 增量序列
void shellSort(RecordList* L,int dlta[],int t){//t为增量序列的长度
    for (int k=0;k<t;k++){
        shellInsert(L,dlta[k]);
    }
}

int main(){
    int n=8;
    int nums[9]={-1,46,25,68,33,33,19,12,80};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//46 25 68 33 33 19 12 80
    
//    int dlta[3]={4,2,1};
    int dlta[3]={7,3,1};
    
    int t=3;
    shellSort(&L,dlta,t); 
	print(L);//12 19 25 33 33 46 68 80 
}

9.3 交换类排序

9.3.1冒泡排序

4-冒泡排序.c
#include <stdio.h>
#include "0-RecordList.h"



//【算法9-5】冒泡排序
RecordList bubbleSort(RecordList L){
    for (int i = 1; i <= L.length; i++) {
        for (int j = 1; j <=L.length-i ; j++) {
            if(L.r[j].key>L.r[j+1].key){
                RecordType temp=L.r[j];
                L.r[j]=L.r[j+1];
                L.r[j+1]=temp;
            }
        }

    }
    return L; 
}

//【算法9-6】改进冒泡排序
//如已排好序,直接跳出
RecordList bubbleSortPlus(RecordList L){
    int flag=1;
    for (int i = 1; i <= L.length&&flag; i++) {
        flag=0;
        for (int j = 1; j <=L.length-i ; j++) {
            if(L.r[j].key>L.r[j+1].key){
                RecordType temp=L.r[j];
                L.r[j]=L.r[j+1];
                L.r[j+1]=temp;
                flag=1;
            }
        }

    }
    return L;
}

int main(){
    int n=8;
    int nums[9]={-1,46,25,68,33,33,19,12,80};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//46 25 68 33 33 19 12 80

    print(bubbleSort(L)); 		//12 19 25 33 33 46 68 80      
    print(bubbleSortPlus(L)); 	//12 19 25 33 33 46 68 80   

}

9.3.2 快速排序

5-快速排序.c
#include <stdio.h>
#include "0-RecordList.h"
//【算法9-7】一趟快速排序 
int QKPass(RecordList* L,int low,int high){
    L->r[0]=L->r[low];//枢轴
    while(low<high){
        while (low<high&&L->r[high].key>=L->r[0].key) --high;
        L->r[low]=L->r[high];
        while (low<high&&L->r[low].key<L->r[0].key) ++low;
        L->r[high]=L->r[low];
    }
    L->r[low]=L->r[0];
    return low;
}

//【算法9-8】快速排序 
void QKSort(RecordList* L,int low,int high){
    int pos;
    if (low<high){
        pos=QKPass(L, low,high);
        QKSort(L, low,pos-1);
        QKSort(L, pos+1,high);
    }
}

int main(){
    int n=8;
    int nums[9]={-1,46,68,12,25,33,80,19,33};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//46 68 12 25 33 80 19 33   

    QKSort(&L,1,L.length); 		    
 	print(L);//12 19 25 33 33 46 68 80

}

9.4 选择类排序

9.4.1 简单选择排序

6-简单选择排序.c
#include <stdio.h>
#include "0-RecordList.h"

//【算法9-9】简单选择排序
RecordList selectSort(RecordList L){
    for (int i = 1; i <= L.length; i++) {
        int k=i;
        for (int j = i+1; j <=L.length ; j++) {
            if (L.r[j].key<L.r[k].key){//k是擂台
                k=j;
            }
        }
        if (k!=i){
            RecordType temp=L.r[i];
            L.r[i]=L.r[k];
            L.r[k]=temp;
        }
    }
    return L;

}

int main(){
    int n=8;
    int nums[9]={-1,33,68,46,33,25,80,19,12};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//33 68 46 33 25 80 19 12

    print(selectSort(L)); 		//12 19 25 33 33 46 68 80   
  
}

9.4.2 树形选择排序

9.4.3 堆排序

7-堆排序.c
#include <stdio.h>
#include "0-RecordList.h"


//【算法9-10】堆的筛选
void HeapAdjust(RecordList* L,int s,int m){
    //已知L[s..m]中记录的关键字除L[s]之外均满足堆的定义
    //本函数调整L[s]的关键字,使L[s..m]成为小顶堆
    RecordType t=L->r[s];
    for(int j=2*s;j<=m;j*=2){
        //沿key较小的孩子结点向下筛选
        if(j<m&&L->r[j].key>L->r[j+1].key){
            j++;//j为key较小的记录的下标
        }
        if(t.key<=L->r[j].key){
            break;
        }
        //t应该插入位置s
        L->r[s]=L->r[j];
        s=j;
    }
    L->r[s]=t;
}
//【算法9-11】建立初始堆
void CreatHeap(RecordList* L){
    int len=L->length;
    for (int i=len/2;i>=1;i--){
        HeapAdjust(L,i, len);
    }
}
//【算法9-12】堆排序
void HeapSort(RecordList* L){
    CreatHeap(L);
    int len= L->length;
    for (int i = len; i >=2 ; i--) {
        L->r[0]=L->r[1];
        L->r[1]=L->r[i];
        L->r[i]=L->r[0];
        HeapAdjust(L,1,i-1);
    }
}


int main(){
    int n=8;
    int nums[9]={-1,46,12,33,72,68,19,80,33};//0号不存储元素 
    RecordList L=create(nums,n);
    print(L);//46 12 33 72 68 19 80 33   

    HeapSort(&L); 		   
    print(L);//80 72 68 46 33 33 19 12
}

9.5 归并类排序

9.5.1 二路归并排序

8- 二路归并排序.c
#include <stdio.h>
#include "0-RecordList.h"

void Merge(RecordList* ,RecordList* ,int ,int ,int );

//【算法9-13】二路归并排序
void MergeSort(RecordList* L,RecordList* CopyL,int left,int right){
    //对上下限值分别为left和right的记录序列L进行归并排序
    //其中copyL为同类型的记录,由于复制保存原记录序列
    int middle;
    if(left<right){
        middle=(left+right)/2;//找中间位置进行划分
        MergeSort(L,CopyL,left,middle);//对左半部分进行递归归并排序
        MergeSort(L,CopyL,middle+1,right);//对右半部分进行递归 归并排序
        Merge(L,CopyL,left,right,middle);//进行归并
    }
}

//【算法9-14】二路归并排序
void Merge(RecordList* L,RecordList* CopyL,int left,int right,int middle){
    int i,p1,p2;
    for (i=left;i<=right;i++){//用copyL记录临时保存待排序记录序列
        CopyL->r[i]=L->r[i];
    }
    p1=left;//左半部分有序记录的起始位置
    p2=middle+1;//右半部分有序记录的起始位置
    i=left;//左半部分开始进行归并
    while(p1<=middle&&p2<=right){
        //取两个有序半区中关键字较小的记录
        if (CopyL->r[p1].key<=CopyL->r[p2].key){
            L->r[i]=CopyL->r[p1];//去较小的记录放到合并后的记录序列中
            p1++;
        } else{
            L->r[i]=CopyL->r[p2];
            p2++;
        }
        i++;
    }
    //剩下的序列无论是左半部分还是右半部分都直接复制到合并后的记录序列中
    while (p1<=middle){
        L->r[i]=CopyL->r[p1];
        i++;
        p1++;
    }
    while (p2<=middle){
        L->r[i]=CopyL->r[p2];
        i++;
        p2++;
    }

}



int main(){
    int n=8;
    int nums[9]={-1,46,12,33,72,68,19,80,33};//0号不存储元素 

    RecordList L=create(nums,n);
    print(L);//46 12 33 72 68 19 80 33
	 
	RecordList CopyL=create(nums,n);
    MergeSort(&L,&CopyL,0,n); 		   
    print(L);//12 19 33 33 46 68 72 80
}

9.5.2自然归并排序

9-自然归并排序.c
#include <stdio.h>
#include <stdlib.h> 
#include "0-RecordList.h"

//【算法9-15】自然归并排序
//将两个有序的子序列R[low..m]和R[m+1..high]归并成一个有序的子序列R[low..high]
void Merge(RecordType* R,int l,int m,int r){
    int i=l,j=m+1,p=0,q;
  
	RecordType *R1;
	R1=(RecordType*) malloc((r-l+1)*sizeof(RecordType));
	if(!R1) return;//申请空间失败 
    while (i<=m&&j<=r){
        //取两个有序半区中关键字较小的记录
        if(R[i].key<=R[j].key){
            R1[p++]=R[i++];
        }else {
            R1[p++]=R[j++];
        }
    }

    //剩下的序列无论是左半部分还是右半部分都直接复制到合并后的记录序列中
    if (i>m){
        for (q = j; q <=r ; q++) {
            R1[p++]=R[q];
        }
    }else {
        for (q=i;q<=m;q++){
            R1[p++]=R[q];
        }
    }

    for (p=0,i=l;i<=r;p++,i++){
        R[i]=R1[p];//归并完成后将结果复制回R[low..high]
    }
}
void NatureMergeSort(RecordType R[],int n){
    int i,sum,low,mid,high;
    while (1){
        i=0;
        sum=1;
        while (i<n-1){
            low=i;
            while (i<n-1&&R[i].key<R[i+1].key){ i++; }
            mid=i++;
            while (i<n-1&&R[i].key<R[i+1].key){ i++; }
            high=i++;
            if (i<=n){
                Merge(R,low,mid,high);
                sum++;
            }
        }
        if (sum==1) break;
    }

}

int main(){
    int n=8;
    int nums[9]={-1,12,24,5,8,3,9,11,7};//0号不存储元素 

    RecordList L=create(nums,n);
    print(L);//12 24 5 8 3 9 11 7
	 
	RecordList CopyL=create(nums,n);
    NatureMergeSort(L.r,9); 		   
    print(L);//3 5 7 8 9 11 12 24
}

9.6 分配类排序

9.6.1 多关键字排序

10-多关键字排序.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <time.h>
/*
Heart 红桃 
Spade 黑桃 
club  梅花 
diamond 方块 
*/
//花色的枚举类 
typedef enum color{
	D=1,C,S,H
}Color; 
//扑克的定义 
typedef struct card{
	Color color;
	int num;
}Card;
//输出花色 
void printColor(Color c){
	switch(c){
		case H: printf("红桃");break;
		case S: printf("黑桃");break;
		case C: printf("梅花");break;
		case D: printf("方块");break;
			
	}
}
//输出扑克 
void printCard(Card card){
	printColor(card.color);
	printf("%-2d",card.num);
} 



//创建一幅扑克 
void creatCards(Card cards[52]){	
   	int colors[4]={D,C,S,H};
   	int nums[13]={1,2,3,4,5,6,7,8,9,10,11,12,13};
   	int n=0;
    for(int i=0;i<4;i++){
        for(int j=0;j<13;j++){
        	Card card;
        	card.color=colors[i];
        	card.num=nums[j];
        	cards[n]=card;   
			n++;  
		}
              
    }
//    printCards(cards);
}
//洗牌 
void shuffleCards(Card cards[52]){	
	srand((unsigned)time(NULL));//用srand()函数来重新播种,用time来充当随机数种子 
	creatCards(cards);	
	//交换52次 
	for (int i=0;i<52;i++){
		
		int r1=rand()%52;//rand()函数产生的随机数是伪随机数 ,和种子有关 
		int r2=rand()%52;
	
		//交换两张牌 
		Card temp=cards[r1];
		cards[r1]=cards[r2];
		cards[r2]=temp;
	}
	
		
	
} 
//打印扑克牌 
void printCards(Card cards[52]){
	for(int i=0;i<52;i++){
		printCard(cards[i]);
		printf(" ");
		if(i%13==12){
			printf("\n");
		}
	}
}
//按最高位优先法MSD排序  花色从小到大  数值从小到大 
void sortCardsWithMSD(Card cards[52]){
	printf("按最高位优先法LSD排序 \n"); 
	//首先按照花色将整副牌分为4组(每组13张牌)
	Card cardsByColor[4][13];
	int cardColorCount[4]={0}; //一个计数器数组,用来记录每组花色加入了多少 
	for (int i=0;i<52;i++){
		int index=cards[i].color-1; //面值从1开始,索引是从0开始的 
		cardsByColor[index][cardColorCount[index]]=cards[i];
		cardColorCount[index]++;		
	} 
//	printf("测试1\n");
//	for(int i=0;i<4;i++){
//		for(int j=0;j<13;j++){
//			printCard(cardsByColor[i][j]); 
//		}		
//		printf("\n");
//	}
	//然后每组在按照面值从小到大进行排序 (选择排序) 
	for(int i=0;i<4;i++){		
		for(int j=0;j<13;j++){
			int m=j; 
			for(int k=j+1;k<13;k++){
				if(cardsByColor[i][k].num<cardsByColor[i][m].num){
					m=k;
				}
				
			}
			if(m!=j){				
				Card temp=cardsByColor[i][j];
				cardsByColor[i][j]=cardsByColor[i][m];
				cardsByColor[i][m]=temp;
			}
		}				
	}
//	printf("测试2\n");
//	for(int i=0;i<4;i++){
//		for(int j=0;j<13;j++){
//			printCard(cardsByColor[i][j]); 
//		}		
//		printf("\n");
//	}
	int n=0;
	//最后将这4组牌收集到一起就是按照花色和面值排好序的有序序列 
	for(int i=0;i<4;i++){
		for(int j=0;j<13;j++){
			cards[n]=cardsByColor[i][j];
			n++;
		}		
	}
}
//按最低位优先法LSD排序  花色从小到大  数值从小到大 
void sortCardsWithLSD(Card cards[52]){
	printf("按最低位优先法LSD排序 \n"); 
	//第一步 先按照面值大小从小到大将整副牌分为13组(每组4张牌)	
	Card cardsByNum[13][4];	
	int cardNumCount[13]={0};//一个计数器数组,用来记录每组面值加入了多少 
	
	for (int i=0;i<52;i++){
		int index=cards[i].num-1;	//面值从1开始,索引是从0开始的 
		cardsByNum[index][cardNumCount[index]]=cards[i];		
		cardNumCount[index]++;		
	} 
	
//	printf("测试1\n");
//	for(int i=0;i<13;i++){
//		for(int j=0;j<4;j++){
//			printCard(cardsByNum[i][j]); 
//		}		
//		printf("\n");
//	}
		
	//第二步 然后将每组牌按照面值的大小收集到一起   从小到大 
	Card CollectByNum[52];	
	int n=0;
	for(int i=0;i<13;i++){
		for(int j=0;j<4;j++){
			CollectByNum[n]=cardsByNum[i][j];
			n++;
		}		
	}
//	printf("测试2\n");
//	printCards(CollectByNum);
	
	//第三步 再对这些牌按照花色摆成4组,每组13张牌 		
	Card cardsByColor[4][13];
	int cardColorCount[4]={0}; //一个计数器数组,用来记录每组花色加入了多少 
	for (int i=0;i<52;i++){
		int index=CollectByNum[i].color-1;
		cardsByColor[index][cardColorCount[index]]=CollectByNum[i];
		cardColorCount[index]++;		
	} 
//	printf("测试3\n");
//	for(int i=0;i<4;i++){
//		for(int j=0;j<13;j++){
//			printCard(cardsByColor[i][j]); 
//		}		
//		printf("\n");
//	}
	
	n=0;
	//第四步 最后再把4组牌按花色的次序收集到一起就是按照花色和面值排好序的有序序列 
	for(int i=0;i<4;i++){
		for(int j=0;j<13;j++){
			cards[n]=cardsByColor[i][j];
			n++;
		}		
	}
//	printf("4");
	 
}

void sortCardsWithBinSort(Card cards[52]){
	printf("按桶排序 \n"); 
	//首先按照花色将整副牌分为4组(每组13张牌)	
	Card cardsByBin[4][13];
	//然后每组在按照面值从小到大进行排序 (桶排序)
	for (int n=0;n<52;n++){
		int i=cards[n].color-1;
		int j=cards[n].num-1;
		cardsByBin[i][j]=cards[n];				
	} 

	int n=0;
	//最后将这4组牌收集到一起就是按照花色和面值排好序的有序序列 
		for(int i=0;i<4;i++){
		for(int j=0;j<13;j++){
			cards[n]=cardsByBin[i][j];
			n++;
		}		
	}
}

void main(){
	printf("排序 按照花色从小到大  数值从小到大 \n");
    Card cards[52] ;   
    printf("洗牌ing.....\n");
	shuffleCards(cards);	//洗牌 
	printf("排序前的牌\n");
	printCards(cards);		//打印扑克牌 
	printf("排序ing.....\n"); 
//	sortCardsWithLSD(cards);//排序 
//	sortCardsWithMSD(cards);//排序 
	sortCardsWithBinSort(cards);
	printf("排序后的牌\n");
	printCards(cards);		//打印扑克牌 

}

9.6.2 链式基数排序

11-链式基数排序.c
#include <stdio.h>
#include <stdlib.h> 
#include "0-RecordList.h"

typedef RecordType DataType; 
#include "链队列.c"

int digit(KeyType key, int m, int r);
	
//【算法9-16】基于链队列的基数排序
void RadixSort(RecordType L[] ,int n,int m,int r){
    //L中的关键字为m为r进制数,L的长度为n
    LQueue** Queue;
    int i,j,k;
    Queue=(LQueue**)malloc(r*sizeof(LQueue*));
    
    for(i=0;i<r;i++){               //初始化r个链队列
        Queue[i]=Init_LQueue();
	}
    for (i = 0;  i<m ; i++) {       //进行m次分配与收集
        for (j=0;j<=n;j++){          //分配
            k=digit(L[j].key,i,r);   //提取当前关键字中第m位的数字值
            InLQueue(Queue[k],L[j]);
        }
        k=0;
        for (j = 0; j < r; j++) {   //收集
            for ( ; !Empty_LQueue(Queue[j]); k++) {
                Out_LQueue(Queue[j],&(L[k]));
            }
        }

    }


}
//【算法9-17】提取关键字中第m位的数字值
int digit(KeyType key, int m, int r){
    int i,d;
    if(m==0){
        return key %r;
    }
    d=r;
    for (i = 1;  i<m ; i++) {
        d*=r;
    }
    return ((int)(key/d)%r);
}


int main(){
    int n=9;
    int nums[10]={-1,921,435,628,285,862,225,448,193,430};//0号不存储元素 

    RecordList L=create(nums,n);
    print(L);//921 435 628 285 862 225 448 193 430

    RadixSort(L.r,9,3,10); 		   
    print(L);//193 225 285 430 435 448 628 862 921
}

9.7 外部排序

9.7.1置换选择排序

9.7.2多路归并外排序

9.8 算法总结

在这里插入图片描述

最后

2023-11-7 19:26:28

我们都有光明的未来
不必感谢我,也不必记得我

祝大家考研上岸
祝大家工作顺利
祝大家得偿所愿
祝大家如愿以偿
点赞收藏关注哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1183164.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Blocking waiting for file lock on the registry index 问题解决

问题表现&#xff1a; cargo build时一直卡在Blocking waiting for file lock on the registry index。 解决方法&#xff1a; 1、之前在linux下出现过一次&#xff0c;采用这种方法解决了&#xff1a;rust - Cargo build hangs with " Blocking waiting for file lock…

【已解决】Windows易升报错0xa0000400,一键修复,无损升级至Windows 10/11 22H2

笔者之前在使用的Windows 10版本是企业版LTSC 1809&#xff0c;想升级到22H2版&#xff0c;不想重装系统和所有软件&#xff0c;听说微软官方的“Windows易升”软件可以无损升级&#xff0c;下载这个软件运行之后&#xff0c;卡在第一步&#xff1a; 软件提示&#xff1a;“若要…

SPSS距离分析

1.距离分析 距离分析在统计学和数据科学中指的是评估和量化对象&#xff08;如观测点、个体、案例等&#xff09;之间差异的过程。在数据集中&#xff0c;每个对象通常由一系列的属性或变量表示。距离分析的目的是为了衡量这些对象在多维空间中的相对位置&#xff0c;通常用于…

MSQL系列(十四) Mysql实战-SQL语句 left join inner join On和Where语句的区别

Mysql实战-SQL语句On和Where语句的区别 前面我们讲解了Join的底层驱动表 选择原理&#xff0c;也知道了基本的内连接外连接两种SQL查询表连接方式 但是我们再查询多表的时候on和where语句到底有什么区别? where是过滤条件 ,不满足where的一定不会出现在结果中on是连接条件, …

Leetcode—2731.移动机器人【中等】

2023每日刷题&#xff08;二十二&#xff09; Leetcode—2731.移动机器人 算法思路 参考自灵茶山艾府 实现代码 class Solution { public:const int MOD 1e9 7;int sumDistance(vector<int>& nums, string s, int d) {int n nums.size();vector<long long…

使用<a>标签进行文件下载出现文件名称乱码、文件名变下划线

在使用a标签下载文件时出现了如图所示文件名称显示错误&#xff0c;原因是因为文件中包含中文导致乱码 解决方法使用axios配合Blob&#xff0c;如果项目中没有安装或者不想安装axios使用Ajax跟fetch也是一样可以解决&#xff1a; 使用axios&#xff08;记得引入axios&#xff0…

JJJ:PCI / PCIE 的一些术语和概念

转发事务和非转发事务 在PCIe&#xff08;Peripheral Component Interconnect Express&#xff09;总线中&#xff0c;存在两种类型的事务&#xff1a;转发事务和非转发事务。 1、转发事务&#xff08;Forwarded Transactions&#xff09;&#xff1a;转发事务是指从一个PCIe…

openvpn使用

如何使用OpenVPN搭建局域安全网_宝塔搭建vpn_幸识SQ的博客-CSDN博客 OpenVPN在CentOS7中最简单的搭建局域网_哔哩哔哩_bilibili 最终的效果是&#xff0c;如果安装好服务端后&#xff0c;会生成一个文件&#xff0c;要用到客户端。 客户端安装后&#xff0c;会多个IP 这样&…

关于unity中 编辑器相关逻辑的记录

prefab 在场景中 , 用这个方法可以获取它的磁盘路径: [MenuItem("Gq_Tools/↓获取prefab路径")] public static void SaveDecalParameters() { var objs Selection.objects; var obj objs[0] as GameObject; Object parentObject Prefab…

Amazon MSK 基于 S3 的数据导出、导入、备份、还原、迁移方案

Amazon MSK&#xff08;Amazon Managed Streaming for Apache Kafka&#xff09;是 Amazon 云平台提供的托管 Kafka 服务。在系统升级或迁移时&#xff0c;用户常常需要将一个 Amazon MSK 集群中的数据导出&#xff08;备份&#xff09;&#xff0c;然后在新集群或另一个集群中…

Linux之打印函数调用依赖关系(六十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

extractvalue报错注入理论及实战

报错注入 什么是报错注入 构造语句&#xff0c;让错误信息中夹杂可以显示数据库内容的查询语句&#xff0c;返回报错提示中包括数据库中的内容 如上图所示&#xff0c;通过group by的报错&#xff0c;我们可以知道列数是多少 输入正确的查询数据库的SQL语句&#xff0c;虽然可…

理解交叉熵(Cross Entropy)

交叉熵&#xff08;Cross-Entropy&#xff09;是一种用于衡量两个概率分布之间的距离或相似性的度量方法。在机器学习中&#xff0c;交叉熵通常用于损失函数&#xff0c;用于评估模型的预测结果与实际标签之间的差异。 在分类问题中&#xff0c;交叉熵损失函数通常用于多分类问…

如何在公文套红过程中设置页码

zOffice的套红功能&#xff0c;是把源文件套入到公文模版的书签中去&#xff0c;将两个文件合成一个&#xff0c;那么源文件的一些设置可能会保留也可能会被重置&#xff0c;那么如何在公文套红中保留页码设置呢&#xff1f;当然是通过zOffice丰富的SDK接口来实现控制了&#x…

WebGL软件项目类型

WebGL&#xff08;Web Graphics Library&#xff09;是一种用于在Web浏览器中渲染3D和2D图形的JavaScript API。它提供了强大的能力&#xff0c;可以用于开发各种类型的项目&#xff0c;包括但不限于以下几种&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xf…

Vue 3 中,watch 和 watchEffect 的区别

结论先行&#xff1a; watch 和 watchEffect 都是监听器&#xff0c;都是用来监听响应式数据的变化并执行相应操作。区别是&#xff1a; watch&#xff1a;需要指明要监听的数据&#xff0c;而且在回调函数中可以获取到属性变化的前后值&#xff1b; 适用于需要精确控制监视…

学习在echarts中优化数据视图dataView样式带表格样式,支持复制功能

学习在echarts中优化数据视图dataView样式 带表格样式 toolbox里有个dataView视图模式&#xff0c;里面的数据没有对整&#xff0c;影响展示效果&#xff0c;情形如下&#xff1a; 像这种标题跟数据没有整齐对应上&#xff0c;看起来乱 改问题解决方案为&#xff0c;option 》…

IO多路复用 Linux C Server-Client 多用户聊天系统

目录 Server-Client mutiplexingServer mutiplexingClient mutiplexing Server-Client 在Linux系统中&#xff0c;IO多路复用是一种机制&#xff0c;它允许一个进程能够监视多个文件描述符&#xff08;sockets、pipes等&#xff09;的可读、可写和异常等事件。这样&#xf…

6-会话、过滤器、监听器

6-会话、过滤器、监听器 文章目录 6-会话、过滤器、监听器会话会话概述为什么需要会话管理会话管理实现的手段 Cookie概述使用时效设置路径设置&#xff1a;特定请求才携带cookie SessionHttpSession的概述HttpSession的使用HttpSession的使用-getSession()方法原理HttpSession…

Django快速指南

开始构建 Web 应用程序不仅需要对编码和设计原则有深入的了解&#xff0c;还需要对安全性和性能坚定不移的承诺。在数字化存在至关重要的时代&#xff0c;构建强大而高效的在线平台的能力是一项具有不可估量价值的技能。本教程专门面向网络工匠&#xff0c;即那些希望将技术线索…