有序表的二路归并

在中国大学MOOC上学习了分别用单链表和顺序表实现有序表的二路归并,为加深印象与理解,自己操作了一下。
有序表中所有有序表以递增或递减的方式有序排列。
在这里插入图片描述
两个有序表L1和L2合并成一个有序表L3。


用单链表实现

在这里插入图片描述

#include<stdio.h>//有序表的二路归并单链表实现
#include<stdlib.h>
typedef struct node
{
	int data;//存放元素
	struct node *next;//指向后继节点的指针
}list;
void Createlist(list *&L,int n)//尾插法建立单链表
{
	list *s, *r;
	int i;
	L = (list*)malloc(sizeof(list));//设置一个头节点
	r = L;//r始终指向尾节点
	printf("输入有序表的元素:\n");
	for (i = 0; i < n; i++)
	{
		s= (list*)malloc(sizeof(list));
		scanf_s("%d", &s->data);
		r->next = s;
		r = s;
	}
	r->next = NULL;//最后的尾节点要指向NULL
}
void combine(list *L1, list *L2, list *&L3)//有序表L1和L2二路归并为有序表L3
{
	list *p =L1->next, *q =L2->next,*r,*s;//p扫描L1,q扫描L2
	L3= (list*)malloc(sizeof(list));//L3为头节点,也用尾插法建立有序表L3
	r = L3;
	while (p != NULL && q != NULL)
	{
		if (p->data < q->data)
		{
			s= (list*)malloc(sizeof(list));
			s->data = p->data;
			r->next = s;
			r = s;
			p = p->next;
		}
		else
		{
			s= (list*)malloc(sizeof(list));
			s->data = q->data;
			r->next = s;
			r = s;
			q = q->next;
		}
	}
	while (p != NULL)
	{
		s= (list*)malloc(sizeof(list));
		s->data = p->data;
		r->next = s;
		r = s;
		p = p->next;
	}
	while (q != NULL)
	{
		s = (list*)malloc(sizeof(list));
		s->data = q->data;
		r->next = s;
		r = s;
		q = q->next;
	}
	r->next = NULL;
}
void print(list *L3)//打印链表
{
	list *p=L3->next;
	while (p != NULL)
	{
		printf("%d ", p->data);
		p = p->next;
	}
}
int main()
{
	list *L1, *L2, *L3;
	int n1, n2;
	printf("输入第一个有序表的长度:\n");
	scanf_s("%d", &n1);
	Createlist(L1, n1);//创建链表
	printf("输入第二个有序表的长度:\n");
	scanf_s("%d", &n2);
	Createlist(L2, n2);
	combine(L1, L2, L3);//合并
	printf("合并后的有序表为:\n");
	print(L3);//打印合并后的链表
	system("pause");
}

运行结果如下:
在这里插入图片描述
L1和L2中每个元素恰好遍历一遍,时间复杂度和空间复杂度都为(m+n)。


用顺序表实现

在这里插入图片描述

#include<stdio.h>//用顺序表实现二路合并
#include<stdlib.h>
#define MaxSize 100
typedef struct//定义顺序表
{
	int data[MaxSize];
	int length;
}list;
void Create(list *&L, int n)//创建顺序表
{
	int i;
	L = (list*)malloc(sizeof(list));
	printf("输入该有序表中的元素:\n");
	for (i = 0; i < n; i++)
	{
		scanf_s("%d", &L->data[i]);
	}
	L->length = n;
}
void combine(list *L1, list *L2, list *&L3)//合并顺序表
{
	int i,j,k;
	i = j = k= 0;
	L3 = (list*)malloc(sizeof(list));
	while (i < L1->length&&j < L2->length)
	{
		if (L1->data[i] < L2->data[j])
		{
			L3->data[k] = L1->data[i];
			i++;
			k++;
		}
		else
		{
			L3->data[k] = L2->data[j];
			j++;
			k++;
		}
	}
	while (i != L1->length)
	{
		L3->data[k] = L1->data[i];
		i++;
		k++;
	}
	while (j != L2->length)
	{
		L3->data[k] = L2->data[j];
		j++;
		k++;
	}
	L3->length = k;
}
void print(list *L3)//打印链表
{
	int i;
	printf("合并后的有序表为:\n");
	for (i = 0; i < L3->length; i++)
	{
		printf("%d ", L3->data[i]);  
	}
}
int main()
{
	list *L1, *L2, *L3;
	int n1, n2;
	printf("输入第一个有序表的长度:\n");
	scanf_s("%d", &n1);
	Create(L1, n1);
	printf("输入第二个有序表的长度:\n");
	scanf_s("%d", &n2);
	Create(L2, n2);
	combine(L1, L2, L3);
	print(L3);
	system("pause");
}

在这里插入图片描述
L1和L2中每个元素恰好遍历一遍,时间复杂度和空间复杂度都为(m+n)。


如果还有更好的方法,请指出。

使用链表二路归并排序的基本思想是将链表递归地分成两个链表,然后对这两个链表进行排序,最后将它们合并成一个有序链表。具体步骤如下: 1.定义一个链表节点类,包含节点值和指向下一个节点的指针。 2.定义一个链表类,包含头节点和尾节点。 3.定义一个二路归并排序函数,该函数接受一个链表作为参数。 4.在二路归并排序函数中,首先判断链表是否为空或只有一个节点,如果是,则直接返回该链表。 5.如果链表不为空且有两个或以上的节点,则将链表分成两个链表,可以使用快慢指针的方法。 6.对这两个链表分别递归调用二路归并排序函数,直到子链表为空或只有一个节点。 7.将两个有序链表合并成一个有序链表,可以使用双指针的方法。 8.返回合并后的有序链表。 以下是使用链表二路归并排序的Python代码示例: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next class LinkedList: def __init__(self): self.head = None self.tail = None def add(self, val): node = ListNode(val) if not self.head: self.head = node self.tail = node else: self.tail.next = node self.tail = node def mergeSort(head): if not head or not head.next: return head # 快慢指针找到链表中点 slow, fast = head, head.next while fast and fast.next: slow = slow.next fast = fast.next.next # 分割链表 mid, slow.next = slow.next, None # 递归排序子链表 left, right = mergeSort(head), mergeSort(mid) # 合并有序链表 dummy = ListNode() cur = dummy while left and right: if left.val < right.val: cur.next, left = left, left.next else: cur.next, right = right, right.next cur = cur.next cur.next = left if left else right return dummy.next ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值