对链表进行归并排序

C作业留了一个对链表进行排序的作业。手头会写的排序没几个。。。又不想用最简单的泡排,,,就尝试了用归并排序。


对链表进行归并排序的有点麻烦的地方在于怎么找到链表的中间节点,由于链表不支持随机访问,所以这里是个比较蛋疼的地方。 最普通的方法就是先遍历一遍,测出链表的长度,然后再根据长度遍历到那个中间的位置。 后来围观同学的代码发现了个好方法。


定义两个指针,开始时都指向表头(是指存有数据的表头,不是那个不存数据只指向下一个位置的表头),然后两个都开始向表尾移动,不过两者的速度不一样,一个每次只走一步,另一个一次走两步。当有一个走到NULL时停止(其实除了一般都是指快指针走到NULL)。这样那个慢的指针很明显这时就走到了链表的中间。那么这时,我们就完成了归并排序唯一一个麻烦的地方,将大问题分治为两个小问题。那么剩下的就是一般归并排序的思路了,将一个大问题分治为小问题解决。


那么下面就放出代码,写的不好还请轻喷

#include <stdio.h>

typedef struct list {
	int num;
	struct list *next;
}list;

list *list_generate();
list *list_scan();
void list_clear(list *head);
void list_push_back(list *head, int val);
void list_print(list *head);
list *list_merge(list *head1, list *head2);
list *list_sort(list *head);

int main() {
	list *a_head;

	printf("Please input a list(end by -1):");
	a_head = list_scan();

	a_head->next = list_sort(a_head->next);

	list_print(a_head);

	list_clear(a_head);

	return 0;
}

list *list_generate() {
	list *head = (list*)malloc(sizeof(list));
	head->next = NULL;
	return head;
}

list *list_scan() {
	int tmp;

	list *head = list_generate();

	while (scanf("%d", &tmp) && tmp != -1)
		list_push_back(head, tmp);

	return head;
}

void list_clear(list *head) {
	list *tmp;
	while (head != NULL) {
		tmp = head->next;
		free(head);
		head = tmp;
	}
}

void list_push_back(list *head, int val) {
	list *to_insert = (list*)malloc(sizeof(list)), *tmp = head;
	to_insert->next = NULL, to_insert->num = val;

	while (tmp->next != NULL) tmp = tmp->next;

	tmp->next = to_insert;
}

void list_print(list *head) {
	list *cur = head->next;

	if (cur == NULL) { puts("There is no element in this list"); return; }

	puts("The new list is:");
	while (cur != NULL) {
		printf("%d", cur->num);
		if (cur->next != NULL) putchar(' ');
		else puts("");
		cur = cur->next;
	}
}

list *list_merge(list *head1, list *head2) {
	list *tmp;

	if (head1 == NULL) return head2;
	if (head2 == NULL) return head1;

	if (head1->num < head2->num) {
		tmp = head1;
		head1 = head1->next;
	}
	else {
		tmp = head2;
		head2 = head2->next;
	}
	tmp->next = list_merge(head1, head2);
	return tmp;
}

list *list_sort(list *head) {
	if (head == NULL)
		return 0;

	list *new_head = head;
	list *head1 = head;
	list *head2 = head;

	while (head2->next != NULL && head2->next->next != NULL) {
		head1 = head1->next;
		head2 = head2->next->next;
	}

	if (head1->next == NULL) return new_head;
	head2 = head1->next;
	head1->next = NULL;
	head1 = head;
	new_head = list_merge(list_sort(head1), list_sort(head2));
	return new_head;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值