倒置鏈表

        最近看了很多對於鏈表的操作,對鏈表的操作無非就是對指針的操作,因此,經常會使人暈頭轉賬,今天跟大家分享一個邏輯不是很複雜,但是對指針的操作較爲複雜的一個例子----倒置鏈表。

        顧名思義,倒置鏈表就是將一個鏈表裏的數據顛倒過來,使得原來的頭成爲尾部,原來的尾部變成第一個節點。當然,一個簡單的方法,可以每次都取得當前鏈表的最後一個節點,將其前插到新生成的鏈表的第一個節點的位置,再將該節點釋放,最後把新生成的鏈表的頭結點首地址賦給原先鏈表的頭結點首地址。但是,這樣做不管是時間複雜度還是空間複雜度,都是比較高的,而如果可以只更改鏈表裏的每個節點的next成員的指向,效率則會大大提高。

        首先我們分析它的手工過程:我們首先要明確鏈表裏的數值遍歷的原理以及各個節點的指向關係。我們用一幅圖來清晰地表示。

        完成倒置鏈表有以下幾點需要注意:

        1、我們現在要做的就是使head的值變成#5,#1中next成員的值變爲NULL,#2中next成員的值變爲#1,#3中next成員的值變爲#2... ...同時還要滿足能夠遍歷整個鏈表,依次更改每一個節點中next的值,不能出現更改後無法找到下一個節點的情況。比如#2的next成員更改爲了#1,當希望繼續找到#3時,原來next空間中存儲的#3的地址值已經被覆蓋爲#1了,因此就不能繼續修改#3中next成員的值了,而且還會造成內存泄漏。

        2、我們發現需要將當前節點的next成員修改爲當前節點的前一個節點的首地址,這就要求我們每次修改完能夠將當前節點的首地址存儲起來。而當前節點的首地址又是它的前驅節點的next成員沒有更改時的值。

        3、第一個節點和最後一個節點情況較爲特殊,因爲第一個節點的next成員被更改爲NULL,而末節點的首地址又應該賦值給head。


        知道了以上三點我們就可以開始編程了:

        1、我們需要一個變量now用來遍歷鏈表,而更改這個變量的時機必須在我們修改當前節點的next成員之前。

        2、需要一個用來存儲當前節點的前驅節點的地址的變量preNode。

        3、每次應先將preNode的值賦值給now的next成員,再將now的值賦值給preNode。

        4、preNode的初值應爲NULL,而不應該是#1,因爲我們遍歷肯定是從第一個節點開始遍歷,第一個節點的前一個節點當然應該是空,這樣做,一是符合語義性,二是根據我們之前所說的操作“每次將preNode的值賦值給now的next成員”,可以不用單獨處理第一個節點,就能夠保證第一個節點的next成員的值爲NULL。

        5、在最後,我們應該將now的值賦值給head,因爲循環結束時,now的值一定是原先鏈表的最後一個節點。

具體代碼如下:

#include <stdio.h>
#include <malloc.h>

typedef struct NODE{
	int data;
	struct NODE *next;
}NODE;

void initLine(NODE **head);
void destoryLine(NODE **head);
void showLine(NODE *head);
void upSideDownLine(NODE **head);

void upSideDownLine(NODE **head) {
	NODE *now = *head;
	NODE *preNode = NULL;
	NODE *temp;

	while (now != NULL) {
		temp = now->next;
		now->next = preNode;
		preNode = now; 
		now = temp;
	}
	*head = preNode;
}

void showLine(NODE *head) {
	NODE *p;

	printf("\n");
	for (p = head; p != NULL; p = p->next) {
		printf("%d ", p->data);
	}
	printf("\n");
}

void destoryLine(NODE **head) {
	NODE *p;

	if (*head == NULL) {
		return;
	}

	while(*head != NULL) {
		p = *head;
		*head = p->next;
		free(p);
	}
}

void initLine(NODE **head) {
	int num;
	NODE *p = *head;

	if (*head != NULL) {
		return;
	}
	printf("請輸入一個數(-1表示結束輸入):");
	scanf_s("%d", &num);
	while (num != -1) {
		if (*head == NULL) {
			*head = (NODE *)calloc(1, sizeof(NODE));
			(*head)->data = num;
			p = *head;
		}
		else {
			p->next = (NODE *)calloc(1, sizeof(NODE));
			p->next->data = num;
			p = p->next;
		}
		printf("請輸入一個數(-1表示結束):");
		scanf_s("%d", &num);
	}
}

void main(void) {
	NODE *head = NULL;

	initLine(&head);
	showLine(head);
	upSideDownLine(&head);
	showLine(head);
	destoryLine(&head);

	fflush(stdin);
	getchar();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章