单向链表反转

    前段时间跟一个同事去面试,他讲到他上次笔试的时候有个题目是单向链表反转, 他说当时他做不出来。 当时稍微思考了下, 应该不难实现, 心里想着有时间做它一做。

    刚好今天闲着没事做, 就决定把它写一写。 咱不是个聪明的人, 我首先想到的方法就是要一个数组把链表保存下来, 然后从数组尾部到首部建表。这个方法直观,不好的是需要额外的数组,当链表的长度很长的时候,这个数组消耗会很大。我们先看下大概出来的图示:


   因为比较直观,也无需做解释了, 直接贴上代码:

oneway_list_t *oneway_list_revert1 (
	oneway_list_t *apList
) 
{
	oneway_list_t **array;
	oneway_list_t *temp;
	oneway_list_t *newHead;
	
	int i = 0, j = 0;
	if (NULL == apList) {
		DERROR("[%s][%d] Error: empty parameter\n");
		return NULL;
	}
	
	// caculate count
	i = 1;
	for (temp = apList->next; temp; temp = temp->next) {
		i++;
	}
	
	DEBUG("list length = %d \n", i);
	
	if (i == 1) {
		return apList;
	}
	
	array = (oneway_list_t **)malloc(sizeof(oneway_list_t *) * i);
	
	if (NULL == array) {
		DERROR("[%s][%d] Error: No memory\n", __FUNCTION__, __LINE__);
		return NULL;
	}
	
	//store list to array
	i = 0;
	for (temp = apList; temp; temp = temp->next) {
		array[i++] = (oneway_list_t *)temp;		
	}
	
	// revert list from array
	newHead = array[i - 1];
	temp = newHead;
	for (j = i - 1; j >= 0; j--) {		
		temp->data = array[j]->data;
		if (j == 0) {
			temp->next = NULL;
		} else {
			temp->next = array[j - 1];
			temp = temp->next;
		}
	}
		
	free(array);
	
	return newHead;	
}

     这个方法做完之后, 考虑到需要额外数组来实现,如果链表很长消耗内存会比较大。于是就考虑是否不需要额外数组就可以实现,脑子里就想能不能把now的next指向前一个,next的next指向now,做一次遍历就可以解决? 简单够了个图,觉得这个方式可行。 看下我画的简图:

    这个图的思想是:

    取连续的三个元素,命名为now, next, head. 修改这三个元素指向下一个的指针。
    结构如下: now->next->head
    now指向它之前的元素,next指向now, 下一个now从head开始. 遍历这个链表按照这样的方式修改  

    实现的难点就是下一轮的now的next要指向到前一轮的next。 看代码:


oneway_list_t * oneway_list_revert2 (
	oneway_list_t *apList
)
{
	oneway_list_t *head, *now, *next, *temp;
	int i = 0;
	if (NULL == apList)
		return NULL;
	
	if (apList->next == NULL)
		return apList;
		
	now = apList;
	next = now->next;
	now->next = NULL;
	do {
		if (next != NULL) {
			head = next->next;
			next->next = now;
		} else {
			head = next;	// new head
			next->next = now;
			break;
		}
		
		if (head != NULL) {
			now = head;
			temp = next;
			next = now->next;			
			now->next = temp;
		} else {
			head = next; // new head
			break;
		}
	} while (1);
	
	return head;
}


    写了两个测试代码:


void test1(void) 
{
	oneway_list_t *head;
	oneway_list_t *temp;
	int i = 0;
	int data[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
	
	// create one-way list from array
	head = new_node();
	temp = head;
	for (i = 0; i < 10; i++) {
		temp->data = data[i];
		if (i < 9) {
			temp->next = new_node();
			temp = temp->next;
		} else {
			temp->next = NULL;
		}
	}
	
	DTRACE("Before revert : \n");
	dump_list(head);
	
	temp = oneway_list_revert1(head);
	
	DTRACE("After revert : \n");
	dump_list(temp);
	
	free_list(temp);	
}

void test2(void)
{
	oneway_list_t *head;
	oneway_list_t *temp;
	int i = 0;
	
	head = new_node();
	temp = head;
	for (i = 0; i < 20; i++) {
		temp->data = i;
		if (i < 19) {
			temp->next = new_node();
			temp = temp->next;
		} else {
			temp->next = NULL;
		}
	}
	
	DTRACE("Before revert : \n");
	dump_list(head);
	
	temp = oneway_list_revert2(head);
	
	DTRACE("After revert : \n");
	dump_list(temp);
	
	free_list(temp);
}

    为了直观,我把链表的地址打印了出来:







   










    完整的代码:

#include <stdio.h>
#include <stdlib.h>

#if 1
#define DEBUG printf
#else
#define DEBUG(...)
#endif
#define DERROR printf
#define DTRACE printf

typedef struct oneway_list_s {
	int data;
	struct oneway_list_s *next;
} oneway_list_t;


oneway_list_t *new_node(void) {
	oneway_list_t *node = (oneway_list_t *)malloc(sizeof(oneway_list_t));
	if (NULL == node)
		return NULL;
	memset(node, 0, sizeof(oneway_list_t));
	node->next = NULL;
	
	return node;
}

void free_list(oneway_list_t* apList)
{
	oneway_list_t *now, *next;
	int i = 0;
	if (NULL == apList)
		return;
		
	now = apList;
	do {
		next = now->next;
		if (NULL != now) {
			free(now);
		}
		now = next;
	} while (next);
}

/**
× @brief 单向链表反转
* 基本思想:用一个数组保存链表,再从数组尾部到首部构造新链表
*/
oneway_list_t *oneway_list_revert1 (
	oneway_list_t *apList
) 
{
	oneway_list_t **array;
	oneway_list_t *temp;
	oneway_list_t *newHead;
	
	int i = 0, j = 0;
	if (NULL == apList) {
		DERROR("[%s][%d] Error: empty parameter\n");
		return NULL;
	}
	
	// caculate count
	i = 1;
	for (temp = apList->next; temp; temp = temp->next) {
		i++;
	}
	
	DEBUG("list length = %d \n", i);
	
	if (i == 1) {
		return apList;
	}
	
	array = (oneway_list_t **)malloc(sizeof(oneway_list_t *) * i);
	
	if (NULL == array) {
		DERROR("[%s][%d] Error: No memory\n", __FUNCTION__, __LINE__);
		return NULL;
	}
	
	//store list to array
	i = 0;
	for (temp = apList; temp; temp = temp->next) {
		array[i++] = (oneway_list_t *)temp;		
	}
	
	// revert list from array
	newHead = array[i - 1];
	temp = newHead;
	for (j = i - 1; j >= 0; j--) {		
		temp->data = array[j]->data;
		if (j == 0) {
			temp->next = NULL;
		} else {
			temp->next = array[j - 1];
			temp = temp->next;
		}
	}
		
	free(array);
	
	return newHead;	
}

/**
* @brief 单向链表反转
×  取连续的三个元素,命名为now, next, head. 修改这三个元素指向下一个的指针。
×  结构如下: now->next->head
×  now指向它之前的元素,next指向now, 下一个now从head开始. 遍历这个链表按照这样的方式修改         
*/
oneway_list_t * oneway_list_revert2 (
	oneway_list_t *apList
)
{
	oneway_list_t *head, *now, *next, *temp;
	int i = 0;
	if (NULL == apList)
		return NULL;
	
	if (apList->next == NULL)
		return apList;
		
	now = apList;
	next = now->next;
	now->next = NULL;
	do {
		if (next != NULL) {
			head = next->next;
			next->next = now;
		} else {
			head = next;	// new head
			next->next = now;
			break;
		}
		
		if (head != NULL) {
			now = head;
			temp = next;
			next = now->next;			
			now->next = temp;
		} else {
			head = next; // new head
			break;
		}
	} while (1);
	
	return head;
}


void dump_list(oneway_list_t *apList)
{
	oneway_list_t *now, *next;
	int i = 0;
	if (NULL == apList)
		return;
		
	now = apList;	
	do {
		next = now->next;
		DTRACE("list[%d] : addr[%d], data[%d]\n", i++, now, now->data);
		now = next;
	} while (now);
	
}

void test1(void) 
{
	oneway_list_t *head;
	oneway_list_t *temp;
	int i = 0;
	int data[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
	
	// create one-way list from array
	head = new_node();
	temp = head;
	for (i = 0; i < 10; i++) {
		temp->data = data[i];
		if (i < 9) {
			temp->next = new_node();
			temp = temp->next;
		} else {
			temp->next = NULL;
		}
	}
	
	DTRACE("Before revert : \n");
	dump_list(head);
	
	temp = oneway_list_revert1(head);
	
	DTRACE("After revert : \n");
	dump_list(temp);
	
	free_list(temp);	
}

void test2(void)
{
	oneway_list_t *head;
	oneway_list_t *temp;
	int i = 0;
	
	head = new_node();
	temp = head;
	for (i = 0; i < 20; i++) {
		temp->data = i;
		if (i < 19) {
			temp->next = new_node();
			temp = temp->next;
		} else {
			temp->next = NULL;
		}
	}
	
	DTRACE("Before revert : \n");
	dump_list(head);
	
	temp = oneway_list_revert2(head);
	
	DTRACE("After revert : \n");
	dump_list(temp);
	
	free_list(temp);
}

void main(void)
{
	test1();
	
	test2();
}













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值