C語言中單鏈表的建立中的地址傳遞和打印以及逆置詳解

插法建立單鏈表:

首先要定義一個單鏈表,其中typedef關鍵字是用來給數據類型重命名的。我這裏命名爲LNode,LinkList,其中LinkList爲聲明的頭指針L。
注意:
在聲明函數的時候,LNode與LinkList等價,不一樣的是LinkList強調這是鏈表,LNode強調這是節點。c++

typedef struct LNode {//定義單鏈表節點類型
	int data;//每一個節點存放一個數據元素
	struct LNode* next;//指針指向下一個節點
}LNode,*LinkList;

下面是用尾插法建立一個單鏈表,首先要初始化一個單鏈表,而後每取一個數據,咱們須要把這個數據插入到表尾:(其中代碼中我建立的單鏈表是帶頭節點的)
下圖中,我爲了方便觀看每取一次數據我換了一個顏色,並進行了相應的編號區分方便你們經過看圖更加全面的理解下面的代碼尤爲是r->next= s和r=s這兩句
尾插法建立單鏈表
值得注意的是:函數

  1. 聲明一個新指針而且要存數據的時候,記得考慮內存分配失敗的狀況,不然將會報錯爲"取消對null指針"xx"的引用"
  2. LinkList List_TailInsert(LinkList *L) 這裏我用到了地址傳遞,記得返回值要爲&L,因此再後來我在main函數裏調用爲List_TailInsert(&L)
  3. 地址傳遞就至關於把某個值變成了全局變量,因此咱們須要經過地址來進行形參的定義;值傳遞就至關於局部變量,只改變當前函數裏的形參的值,並不影響實參的值。另外:c語言裏的地址傳遞至關於c++中的&引用調用同樣。
LinkList List_TailInsert(LinkList *L) {
	int x;
	//*L = NULL;
	*L = (LinkList)malloc(sizeof(LNode));//初始化空表
	if (L==NULL) {//考慮內存分匹配失敗的狀況
		return 0;
	}
	LNode *s,*r = *L;//定義兩個指針使他們分別都和頭指針指向相同
	scanf_s("%d", &x);
	while (x!=9999)
	{
		s = (LNode *)malloc(sizeof(LNode));//給s分配一個新的節點
		if (s == NULL) {//考慮內存分匹配失敗的狀況
			return 0;
		}
		s->data = x;//把x賦值給新的節點
		if (r == NULL) {//考慮內存分匹配失敗的狀況
			return 0;
		}
		r->next= s;//讓r的下一個指針與s指針指向相同,也就是在r節點後插入s
		r=s;//永遠保持r只想最後一個節點
		printf("--------------------");
		scanf_s("%d", &x);
		
	}
	if (r == NULL) {
		return 0;
	}
	r->next = NULL;

	return *L;
}

下面就是打印單鏈表和主函數裏的相應調用了:指針

void GetElem(LinkList L) {
	LNode* p;
	int j = 0;
	p = L;
	while (p!=NULL)
	{
		p = p->next;
		printf("輸入的值爲:%d,地址爲:%p\n", p->data, p);
	}
 }

int main() {
	LinkList L;
	L=List_TailInsert(&L);
	GetElem(L);
}

所有代碼:code

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

typedef struct LNode {
	int data;
	struct LNode* next;
}LNode,*LinkList;

LinkList List_TailInsert(LinkList *L) {
	int x;
	//*L = NULL;
	*L = (LinkList)malloc(sizeof(LNode));
	if (L==NULL) {
		return 0;
	}
	LNode *s,*r = *L;
	scanf_s("%d", &x);

	while (x!=9999)
	{
		s = (LNode *)malloc(sizeof(LNode));
		if (s == NULL) {
			return 0;
		}
		s->data = x;
		if (r == NULL) {
			return 0;
		}
		r->next= s;
		r=s;
		printf("--------------------");
		scanf_s("%d", &x);
		
	}
	if (r == NULL) {
		return 0;
	}
	r->next = NULL;

	return *L;
}

void GetElem(LinkList L) {
	LNode* p;
	int j = 0;
	p = L;
	while (p!=NULL)
	{
		p = p->next;
		printf("輸入的值爲:%d,地址爲:%p\n", p->data, p);
	}
 }

int main() {
	LinkList L;
	L=List_TailInsert(&L);
	GetElem(L);
}

結果:
在這裏插入圖片描述
不建立頭結點的尾插法建立單鏈表的方法:
值得注意的是,打印單鏈表的函數中,不能先讓p指針指向p的下一個指針指向的位置,須要先打印再進行此操做blog

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

typedef struct LNode {
	int data;
	struct LNode* next;
}LNode, * LinkList;

LinkList List_TailInsert(LinkList* L) {
	int x;
	int i = 0;
	*L = NULL;
	//*L = (LinkList)malloc(sizeof(LNode));
	//if (L == NULL) {
		//return 0;
	//}
	LNode * s, * r = *L;
	//LNode* s = *L;
	scanf_s("%d", &x);
	s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL) {
		return 0;
	}
	s->data = x;
	*L = s;//L指針指向s指針所指向的節點
	r = *L;.//r指針指向L指針所指向的節點,這裏指向s也是一個道理
	printf("^^^^^^^^^^^^^^^");
	scanf_s("%d", &x);
	while (x != 9999)//裏面的循環就和有頭結點的循環同樣了
	{	
		s = (LNode*)malloc(sizeof(LNode));
		if (s == NULL) {
			return 0;
		}
		s->data = x;
		if (r == NULL) {
			return 0;
		}
		r->next = s;
		r = s;
		printf("--------------------");
		scanf_s("%d", &x);

	}
	if (r == NULL) {
		return 0;
	}
	r->next = NULL;

	return *L;
}

//打印單鏈表
void GetElem(LinkList L) {
	LNode* p;
	int j = 0;
	p = L;
	while (p != NULL)
	{
		printf("輸入的值爲:%d,地址爲:%p\n", p->data, p);
		p = p->next;
		
	}
}

int main() {
	LinkList L;
	L = List_TailInsert(&L);
	GetElem(L);
}

結果:
在這裏插入圖片描述圖片

頭插法創建單鏈表:

首先須要初始化單鏈表,而後每取一次數據就向表頭插一個數據。
值得注意的是,這裏的指針L要表示指針L的下一個指針時須要帶括號,不然就會報錯"表達式必須包含指向結構或聯合的指針類型"內存

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

typedef struct LNode {
	int data;
	struct LNode* next;
}LNode, * LinkList;

LinkList List_HeadInsert(LinkList* L) {
	LNode* s;
	int x;
	*L = (LinkList)malloc(sizeof(LNode));//建立頭結點
	(*L)->next = NULL;//初始爲空鏈表
	scanf_s("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		if (s == NULL) {
			return 0;
		}
		s->data = x;
		s->next = (*L)->next;//s指針的下一個指針指向l的下一個指針,也就是s指針的下一個指針指向null
		(*L)->next = s;//l指針的下一個指針指向s指針的所指的方向
		printf("--------------------");
		scanf_s("%d", &x);

	}
	return *L;
}

void GetElem(LinkList L) {
	LNode* p;
	int j = 0;
	p = L;
	while (p!=NULL)
	{
		p = p->next;
		printf("輸入的值爲:%d,地址爲:%p\n", p->data, p);
	}
 }

int main() {
	LinkList L;
	L = List_HeadInsert(&L);
	GetElem(L);
}

結果:
在這裏插入圖片描述
由此可看,單鏈表的數據是逆置的,因此咱們須要考慮單鏈表逆置io

單鏈表逆置

下圖是單鏈表逆置的圖像解析,爲了方便更好理解代碼,這個思路有點像後插法,咱們須要聲明兩個指針變量。一個用來引導指針L一個用來尋找後續節點。
在這裏插入圖片描述
代碼以下:class

LinkList Reverse(LinkList L) {
	LNode * p,* r;
	p = L->next;
	L->next = NULL;//斷鏈

	while (p!=NULL)
	{
		r = p->next;
		p->next = L->next;
		L->next = p;
		p = r;
	}
	return L;
}

綜合上述,頭插法創建單鏈表的所有代碼爲:變量

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

typedef struct LNode {
	int data;
	struct LNode* next;
}LNode, * LinkList;

LinkList List_HeadInsert(LinkList* L) {
	LNode* s;
	int x;
	*L = (LinkList)malloc(sizeof(LNode));//建立頭結點
	(*L)->next = NULL;//初始爲空鏈表
	scanf_s("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		if (s == NULL) {
			return 0;
		}
		s->data = x;
		s->next = (*L)->next;//s指針的下一個指針指向l的下一個指針,也就是s指針的下一個指針指向null
		(*L)->next = s;//l指針的下一個指針指向s指針的所指的方向
		printf("--------------------");
		scanf_s("%d", &x);

	}
	return *L;
}

void GetElem(LinkList L) {
	LNode* p;
	int j = 0;
	p = L;
	while (p!=NULL)
	{
		p = p->next;
		printf("輸入的值爲:%d,地址爲:%p\n", p->data, p);
	}
 }
 //單鏈表逆置
LinkList Reverse(LinkList L) {
	LNode * p,* r;
	p = L->next;
	L->next = NULL;//斷鏈

	while (p!=NULL)
	{
		r = p->next;
		p->next = L->next;
		L->next = p;
		p = r;
	}
	return L;
}

int main() {
	LinkList L;
	L = List_HeadInsert(&L);
	L = Reverse(L);
	GetElem(L);
}

結果爲:
在這裏插入圖片描述

相關文章
相關標籤/搜索