数据结构ky备战Day6 - 排序

折半插入

// 折半插入
void BinSort(int a[], int n){
	for(int i = 2; i <= n; i ++){
		int x = a[i];
		// 查找待插入元素
		int mid;
		int low = 1, high = i - 1;
		while(low <= high){
			mid = (low + high) / 2;
			if(a[i] == mid) break;
			else if(a[i] < mid) high = mid - 1;
			else low = mid + 1;
		}
		for(int j = i - 1; j>= low; j --) a[j + 1] = a[j];  // 向前移动元素
		a[low] = x;
	}
}

选择排序(链表)

// 选择排序(链表)
LinkList* SelectSort(ListNode *head){
	if(head == NULL) return head;
	Node *p;
	for(p = head->next; p != NULL; p = p->next){
		Node *q ; // 遍历指针(往后查找最小的值)
		Node *Min == NULL; // 用来保存最小的结点
		// 从p结点开始往后查找最小的值
		for(q = p->next;q != NULL; q = q->next){
			if(q->data < s->data) Min = q;
		}
		if(Min == NULL) continue;
		// 交换两者的值
		int x = p->data;
		p->data = Min->data;
		Min->data = p->data;
	}
	return head; // 返回链表
}

快速排序

// 快速排序 平均时间复杂度 O(nlog2n) 空间复杂度 O(log2n) (递归栈)
int Partition(int a[], int low, int high){  // 一次划分
	int x = a[low];  // 选择基准记录
	while(low < high){
		while(a[high] >= x && low < high) high --;  // 找到比枢轴小的元素
		if(low < high) a[low] = a[high], low ++;  // 将其送入"空"单元 并且low指针加一
		while(a[low] <= x && low < high) low ++;  // 找到比枢轴大的元素
		if(low < high) a[high] = a[low], high --; // 将其送入“空”单元,并且high指针加一
	}
	a[low] = x;  // 最后将枢轴送入“空单元”
	return low;  // 返回枢轴的下标
}

void QuickSort(int a[], int low, int high){
	if(low < high){
		int pos = Partition(a, low, high);  // 进行一次划分
		QuickSort(a, low, pos - 1);  // 对左子表进行快速排序
		QuickSort(a, pos + 1, high);  // 对右子表进行快速排序
	}
}

堆排序

// 堆排序 时间复杂度 O(nlog2n) 空间复杂度 O(1) 
void HeapReBuild(int a[], int k, int m){  // 堆的重建
// 重建堆,k是最上面的根的下标,m是完全二叉树最后一个下标
	int root = a[k];  // 保存根记录
	int i = k, j = 2 * k ; // i是根结点下标,j是根节点的左子树下标
	bool flag = false; // 循环退出的标志变量
	while(j < m && !flag){
		if(j + 1 < m && a[j] < a[j + 1]) j = j + 1; // 如果存在右子树且右子树大的话,j右移一位指向右子树
		if(root >= a[j]) flag = true;  // 根结点已经满足大根堆条件 直接退出
		else{
			a[i] = a[j];
			i = j;  // 使用i保留当前子树的下标
			j = 2 * i; // j继续往子树寻找比root大的结点
		}
	}
	a[i] = root; // 最后i空出的位置就是原根节点插入的位置
}

void HeapCreate(int a[], int n){ // 构造初始堆
	for(int i = n / 2; i >= 1; i --){ // 从最后一个叶节点的双亲结点开始直到根节点
		HeapReBuild(a, i, n); // 根是i,最后一个元素是n
	}
}

void HeapSort(int a[], int n){ // 堆排序
	HeapCreate(a, n); // 首先构造初始堆
	for(int i = n; i >= 2; i --){ // 从最后一个元素开始调整
		// 堆顶和堆尾呼唤
		int b = a[1]; 
		a[1] = a[i];
		a[i] = b;
		HeapReBuild(a, 1, i - 1); // 堆的重建 从根结点开始调整,最后元素是i-1
		
	}
}

归并排序

// 归并排序 时间复杂度 O(nlog2n) 空间复杂度 O(n) 主要在归并数组用到 
void Merge(int a[], int low, int mid, int high){ // 把两个有序表合成一个的抄过来即可
	int *A = (int *)malloc(sizeof(int) * (high - low + 1) );  // 新建存储单元
	int i = low, j = mid + 1;  // 分别遍历左表和右表
	int k = 0; // 新数组A的下标
	while((i <= mid) && (j <= high)){
		if(a[i] <= a[j]) A[k++] = a[i++];  // 在等于的情况下,优先放左边的 保证稳定性
		else A[k++] = a[j++];  
	}
	// 对剩下没有遍历到的元素进行赋值
	while(i <= mid) A[k++] = a[i++];
	while(j <= high) A[k++] = a[i++];
	
	// 将合并好的元素放回原表
	k = 0, i = low;
	while(i<=high) a[i++] = A[k++];
	free(A);
}

void MergeSort(int a[], int low, int high){
	int mid;
	while(low < high){
		mid = (low + high) / 2;
		MergeSort(a, low, mid); // 对前半段归并排序
		MergeSort(a, mid + 1, high); // 对后半段归并排序
		Merge(a, low, mid, high);  // 排序好的两段合并
	}
}x
posted @ 2023-10-26 22:27  yuezi2048  阅读(11)  评论(0编辑  收藏  举报