C語言鏈表詳解及代碼分析
什么是鏈表
鏈表是一種常見的重要的數(shù)據(jù)結構。它是動態(tài)地進行存儲分配的一種結構。鏈表和數(shù)組比較,不用事先確定存儲空間,而是根據(jù)需要開辟內(nèi)存單元。
下圖1是最簡單的一種鏈表(單向鏈表)的結構

第 0 個結點稱為頭結點,它存放有第一個結點的首地址,它沒有數(shù)據(jù),只是一個指針變量。以下的每個結點都分為兩個域,一個是數(shù)據(jù)域,存放各種實際的數(shù)據(jù),如學號 num,姓名 name,性別 sex 和成績 score 等。另一個域為指針域,存放下一結點的首地址。鏈表中的每一個結點都是同一種結構類型。
環(huán)境構建
用的Visual Studio 2019軟件



在源文件中添加C文件

建立靜態(tài)鏈表
包含所需要的頭文件
#include<stdio.h> //標準輸入輸出頭文件 #include<stdlib.h>//包含了C、C++語言的最常用的系統(tǒng)函數(shù)
宏定義相關變量
#define LEN sizeof(struct Student)//宏定義節(jié)點長度得命名 #define TYPE struct Student//宏定義結構體變量命名
創(chuàng)建一個結構體
struct Student//定義一個學生類型結構體,包括學號,分數(shù)
{
long num;
float score;
struct Student* next;//next是指針變量,指向結構體變量
};
//指向結構體對象得指針變量既可以指向結構體變量,也可以指向結構體數(shù)組中得元素
主函數(shù)
int main()
{
TYPE* head,*p;//定義頭指針
struct Student a,b,c;//定義三個結構體變量
a.num = 101; a.score = 20;//分別對三個結點賦值
b.num = 102; b.score = 20;
c.num = 103; c.score = 20;
/*1、A.B則A為對象或者結構體
2、A->B則A為指針,->是成員提取,A->B是提取A中的成員B,A只能是指向類、結構、聯(lián)合的指針;*/
head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;
p = head;//把首地址給變量
do
{
printf("%ld %5.1f\n",p->num,p->score);//輸出每個結點信息
p = p->next;//使P指向下一個結點
} while (p != NULL);//直到指針域指向空值
return 0;
}
結果展示

說明
將第一個結點的起始地址賦值給頭指針head,將第二個結點的起始地址賦值給第一個結點的next成員,將第二個結點的起始地址賦給第一個結點的next…第三個結點的next賦值為NULL,這就形成了簡單的鏈表。
建立動態(tài)鏈表
所謂建立動態(tài)鏈表是指在程序執(zhí)行過程中從無到有地建立起一個 鏈表,即一個一個地開辟結點和輸入各結點數(shù)據(jù),并建立起前后相連的關系。
包含所需要的頭文件
#include<stdio.h> //標準輸入輸出頭文件 #include<stdlib.h>//包含了C、C++語言的最常用的系統(tǒng)函數(shù) #include<malloc.h>//動態(tài)存儲分配函數(shù)頭文件
宏定義相關變量
#define LEN sizeof(struct Student)//宏定義節(jié)點長度得命名 #define TYPE struct Student//宏定義結構體變量命名
創(chuàng)建一個結構體
struct Student//定義一個學生類型結構體,包括學號,分數(shù)
{
long num;
float score;
struct Student* next;//next是指針變量,指向結構體變量
};
//指向結構體對象得指針變量既可以指向結構體變量,也可以指向結構體數(shù)組中得元素
建立鏈表函數(shù)
TYPE* Creat(void)//定義函數(shù),此函數(shù)返回一個指向鏈表頭的指針
{
TYPE* head;//定義頭指針
TYPE* p1,*p2;//定義兩個 指針變量用來相互保存
number = 0;//開始時,結點清零
p1 = p2 = (TYPE*)malloc(LEN);//創(chuàng)建存儲空間
printf("請按格式輸入學生學號,分數(shù)\n");//輸出提示信息
printf("例如101,1 并以0,0結束\n");
scanf("%ld,%f", &p1->num, &p1->score);//按格式輸入第一個結點的信息
head = NULL;//第一個結點頭指針賦空值
while (p1->num!=0)//循環(huán)直到輸入學生學號為0,就結束
{
number++;//結點自增
if (number == 1)//如果只有一個結點,那么頭指針指向第一個輸入的結點
head = p1;
else
p2->next = p1;//如果大于1個,那么要用next保存前一個結點的信息
p2 = p1;//保存前一個結點信息
p1 = (TYPE*)malloc(LEN);//開辟新的結點
scanf("%ld,%f", &p1->num, &p1->score);//輸入下一個結點信息
}
p2->next = NULL;//循環(huán)結束,將指向信息賦空值
return (head);//返回首地址
}
主函數(shù)
int main()
{
TYPE* pt;//定義一個結構體指針變量
pt = Creat();//函數(shù)返回鏈表第一個結點的地址
printf("\nnum:%ld\nscore:%5.lf\n", pt->num,pt->score);//輸出第一個結點的成員值
return 0;
}
結果展示

== 文中最后結果顯示的是第一個結點的內(nèi)容,作為有強大功能的鏈表,對他的操作當然有許多,比如:鏈表的創(chuàng)建,修改,刪除,插入,輸出,排序,反序,清空鏈表的元素,求鏈表的長度等等。==
鏈表的輸出
用循環(huán)直接可以輸出鏈表
輸出函數(shù)
void print(TYPE * head)
{
TYPE * p;//定義指針
printf("\nNOW These %d records are:\n");//輸出顯示信息
p = head;//使p指向第一個結點
if(head!=NULL)//輸出第一個結點后的信息
do {
printf("%ld %5.1f\n",p->num,p->score);
p = p->next;//指向下個結點
} while (p != NULL);
}
主函數(shù)
int main()
{
TYPE * pt;//定義一個結構體指針變量
pt = Creat();//函數(shù)返回鏈表第一個結點的地址
print(pt);//輸出調用
return 0;
}
鏈表的修改
修改函數(shù)
修改鏈表節(jié)點值很簡單。下面是一個傳入鏈表和要修改的節(jié)點,來修改值的函數(shù).
void change(TYPE* head, int n) //修改指定位置的結點的信息
{
TYPE* p = head;//傳入首地址
int i = 0;
while (i < n && p != NULL) {
p = p->next;
i++;
}//找到相應的位置結點
if (p != NULL) {
printf("輸入要修改的值\n");
scanf("%ld,%f", &p->num, &p->score);//輸入下一個結點信息
}
else
printf("節(jié)點不存在\n");
}
主函數(shù)
int main()
{
TYPE* pt;//定義一個結構體指針變量
pt = Creat();//函數(shù)返回鏈表第一個結點的地址
change(pt,2);//修改相關結點的信息,假設修改第2+1個
print(pt);//輸出調用
return 0;
}
##鏈表的刪除
刪除鏈表的元素也就是把前節(jié)點的指針域越過要刪除的節(jié)點指向下下個節(jié)點。即:p->next = q->next;然后放出q節(jié)點的空間,即free(q);

刪除函數(shù)
void delet(TYPE* head, int n) {
TYPE* p = head, * in;//定義兩邊指針
int i = 0;
while (i < n && p != NULL) {
in = p;//找到左邊的
p = p->next;//找到右邊的
i++;
}
if (p != NULL) {
in->next = p->next;//將左右鏈接
free(p);//釋放中間結點
}
else {
printf("節(jié)點不存在\n");
}
}
主函數(shù)
int main()
{
TYPE* pt;//定義一個結構體指針變量
pt = Creat();//函數(shù)返回鏈表第一個結點的地址
delet(pt,1);//刪除第1+1個結點
print(pt);//輸出調用
return 0;
}
輸出結果

##鏈表的插入
我們可以看出來,插入節(jié)點就是用插入前節(jié)點的指針域鏈接上插入節(jié)點的數(shù)據(jù)域,再把插入節(jié)點的指針域鏈接上插入后節(jié)點的數(shù)據(jù)域。根據(jù)圖,插入節(jié)點也就是:e->next = head->next; head->next = e;
增加鏈表節(jié)點用到了兩個結構體指針和一個int數(shù)據(jù)。

插入函數(shù)
void insert(TYPE* head, int n) {//鏈表的插入
TYPE* p = head, * in;
int i = 0;
while (i < n && p != NULL) {
p = p->next;
i++;//找到相應結點
}
if (p != NULL) {
in = (TYPE*)malloc(sizeof(TYPE));//開辟新的空間
printf("輸入要插入的值\n");
scanf("%ld,%f", &in->num, &in->score);//輸入新的結點信息
in->next = p->next;//填充in節(jié)點的指針域,也就是說把in的指針域指向p的下一個節(jié)點
p->next = in;//填充p節(jié)點的指針域,把p的指針域重新指向in
}
else {
printf("節(jié)點不存在\n");
}
}
主函數(shù)
int main()
{
TYPE* pt;//定義一個結構體指針變量
pt = Creat();//函數(shù)返回鏈表第一個結點的地址
insert(pt, 1);//從1+1后插入
print(pt);//輸出調用
return 0;
}
結果顯示

出現(xiàn)的問題
1、出現(xiàn)scanf 和printf 在VS2019中使用時會出錯,解決辦法如下


到此這篇關于C語言鏈表詳解及代碼分析的文章就介紹到這了,更多相關C語言鏈表詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C/C++使用socket實現(xiàn)判斷ip是否能連通
這篇文章主要為大家詳細介紹了C/C++如何使用socket實現(xiàn)判斷ip是否能連通,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解一下2023-07-07
C++的靜態(tài)聯(lián)編和動態(tài)聯(lián)編詳解
這篇文章主要介紹了C++的靜態(tài)聯(lián)編和動態(tài)聯(lián)編詳解,對于深入理解C++編譯運行原理有很大幫助,需要的朋友可以參考下2014-07-07
vscode使用cmake時將命令行參數(shù)傳遞給調試目標的方法
這篇文章主要介紹了vscode使用cmake時將命令行參數(shù)傳遞給調試目標,下面介紹了一個示例,將參數(shù)first_arg, second-arg和third arg傳遞給程序(此處需要注意,third arg中間雖然存在空格,但是仍然被視作一個參數(shù)),需要的朋友參考下吧2024-03-03

