生活随笔
收集整理的這篇文章主要介紹了
C语言实现线性动态(单向)链表【详细步骤】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 什么是鏈表
- 為什么不用結構體數組
- 鏈表的操作
- 代碼及運行結果
什么是鏈表
鏈表是數據結構里面的一種,線性鏈表是鏈表的一種,線性鏈表的延伸有雙向鏈表和環形鏈表。在編程語言中優化數據結構可以在處理大數據時大大降低程序的空間復雜性和時間復雜性。這里我只用一個簡單的例子——線性單向鏈表為例,說明C語言是如何實現該結構的。
鏈表的元素是由結構體來實現struct table *p。結構體中有一個成員是結構體指針struct table *next,而這個結構體指針的類型和此結構體類型相同。除鏈表最后一個元素外,每一個結構體的指針都指向鏈表中下一個元素的結構體,最后一個元素的結構體指針為空(NULL)。保存鏈表時,只需要記錄下鏈表的頭指針,即鏈表中第一個結構體的地址即可。添加一個鏈表元素時,都需要單獨申請一段內存;刪除時則將其釋放掉。在查找鏈表時,只需要順著結構體指針的順序一個一個往下查找,直到查找的結構體中的成員指針。以下是一個鏈表結構的示意:
struct Student
{
int ID
;
char[20];
int marks
[5];
struct Student
*next
;
}
為什么不用結構體數組
有人會有問為什么不直接用一個結構體數組代替鏈表,結構體數組占據的內存空間是連續的,如果使用malloc指令一樣可以動態存儲,而且連續的內存空間肯定比不確定的內存空間效果要好。但是如果對一個動態數組插入或者刪除元素的話,它后面的所有元素都需要變動位置,因此修改數組會比鏈表要難的多。但它的優點在于查找方式很靈活,每一個元素相對于數組首元素地址都有一個偏移量i,因此對于數組來說既可以順向查找也可以反向查找,還可以二分法查找。
由于鏈表的每一個元素都有一段內存,這些內存未必是連續的,加上鏈表本身會比結構體數組多一個指向下一個元素的結構體指針,因此從節省內存的角度看鏈表是不如數組的。但是鏈表刪除元素的時候(假設這個元素是a[k])只需要a[k-1]的next指針指向a[k+1],再把a[k]的內存釋放即可,非常方便;插入元素的時候(假設這個元素是a[n]),只需要a[n-1]的next指針指向a[n]再將a[n]的指針指向a[n+1]即可,相比于數組來說只修改了兩個元素,速度快而且非常方便。
鏈表的操作
鏈表的操作分為——創建表、插入元素、刪除元素、清空表、查找表、打印表。其中插入/刪除的元素可以是一個也可以說多個。鏈表從存儲類型上來分可以分為靜態鏈表和動態鏈表,靜態鏈表是事先編寫好的鏈表,占用的內存是靜態存儲區的內存,使用時不可以對其中的元素進行刪減,只能查找;動態鏈表是按照程序要求生成的鏈表,存放于動態存儲區,結構比較靈活,每一個元素都占據一部分存儲空間,如果要刪除元素,則釋放該位置的內存;如果要添加元素,則申請一個結構體內存區的內存。
創建表
創建鏈表需要兩個指針,一個作為先行指針(*p1),開辟內存并保存結構體的值;一個作為緩存指針(*p2),保留先行指針的所有值并且將它的next指向先行指針。構建鏈表時,先行指針賦一個值,后行指針保存一個值并且后行指針的next指向先行指針。賦值終止時,先行指針的next指向NULL,同時將先行指針賦值給后行指針,鏈表即構建完畢
代碼窗口可以通過鍵盤的"←"和"→"查看。
struct Student
* input()
{struct Student
*p1
,*p2
,*head
=NULL; printf("************************動態鏈表實驗***********************\n【輸入動態鏈表】\n");printf("請依次輸入學號 姓名 身高(cm) 體重(kg)(用空格間隔,學號輸入0結束):\n");p2
=p1
=(struct Student
*)malloc(LEN
);scanf("%d %s %f %f",&p1
->ID
,&p1
->name
,&p1
->height
,&p1
->weight
);if(p1
->ID
==0)return(head
);else head
=p1
;while(p1
->ID
!=0){p2
->next
=p1
;p2
=p1
;p2
->BMI
=(float)p2
->weight
/(p2
->height
/100)/(p2
->height
/100);p1
=(struct Student
*)malloc(LEN
);scanf("%d %s %f %f",&p1
->ID
,&p1
->name
,&p1
->height
,&p1
->weight
);}p2
->next
=NULL;return(head
);
}
刪除元素
刪除元素鏈表的第n個元素只需要將第n-1個元素的next指針指向第n+1個元素,再將第n個元素的內存釋放即可,我這里是寫的其中一個例子,根據關鍵字學號(int stdID)刪除表中的某個元素,同時返回刪除后的鏈表首地址(如果刪的是第一個元素,則鏈表首地址會變)
代碼窗口可以通過鍵盤的"←"和"→"查看。
struct Student
*delate(struct Student
*head
,int stdID
)
{struct Student
*p1
,*p2
;if(head
->ID
==stdID
){p1
=head
->next
;free(head
);return p1
;}for(p1
=head
;p1
!=NULL;p2
=p1
,p1
=p1
->next
){if(p1
->ID
==stdID
){p2
->next
=p1
->next
;free(p1
);return head
; }}return NULL;
}
插入元素
插入元素的原理是,假設要在第n個元素前插入一個元素。首先判斷它是不是首元素,如果是,則修改頭指針指向該元素,并將該元素的next指向原來的頭指針。如果不是首元素,是第k個元素之前插入一個元素,則將第k-1個元素的next指針指向插入元素(或者子表)的地址(或者頭指針),將插入元素的next指針(或尾指針)指向第k個元素。本示例代碼是根據一個學號(主要關鍵字)插入一個元素(或者子表)的函數,返回鏈表的首地址(因為如果在第一個元素前面插入,可能改變鏈表的首地址)。
代碼窗口可以通過鍵盤的"←"和"→"查看。
struct Student
*insert(struct Student
*head
,int stdID
,struct Student
*insertstd
)
{struct Student
*p1
,*p2
,*p
;for(p
=insertstd
;p
->next
!=NULL;p
=p
->next
);if(head
->ID
==stdID
){p
->next
=head
;return insertstd
;}for(p1
=head
;p1
!=NULL;p2
=p1
,p1
=p1
->next
){if(p1
->ID
==stdID
){p2
->next
=insertstd
;p
->next
=p1
;return head
; }}return NULL;
}
代碼及運行結果
完整代碼及注釋如下:
代碼窗口可以通過鍵盤的"←"和"→"查看。
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
#define LEN sizeof(struct Student)
struct Student
{int ID
;char name
[20];float height
;float weight
;float BMI
;struct Student
*next
;
};
struct Student
*input();
void output(struct Student
* head
);
struct Student
*delate(struct Student
*head
,int stdID
);
struct Student
*insert(struct Student
*head
,int stdID
,struct Student
*insertstd
);
int append(struct Student
*head
);
struct Student
*isexist(struct Student
*head
,int stdID
);
int main()
{struct Student
*present
;int choice
;bool next
;int stdID
; printf("**********動態鏈表實驗**********\n初始化一個鏈表:\n");present
=input();do{printf("請選擇:\n|1:插入元素(子表)\n|2:刪除元素\n|3:續表\n|4:查找表\n");scanf("%d",&choice
); switch(choice
) {case 1:printf("請輸入插入地點的后一個同學的學號: ");scanf("%d",&stdID
);if(isexist(present
,stdID
)==NULL){printf("該學生不存在!\n");break;}present
=insert(present
,stdID
,input());printf("插入元素后的鏈表為:\n"); output(present
);break;case 2:printf("請輸入刪除元素的學號: ");scanf("%d",&stdID
);if(isexist(present
,stdID
)==NULL){printf("該學生不存在!\n");break;}present
=delate(present
,stdID
);printf("刪除后的鏈表為:\n"); output(present
);break;case 3:append(present
);printf("續表后的鏈表為:\n");output(present
);break;case 4:printf("當前鏈表為:\n"); output(present
);break;}printf("是否繼續(Yes:1,No:0): ");scanf("%d",&next
);fflush(stdin);}while(next
);return 0;
}
struct Student
* input()
{struct Student
*p1
,*p2
,*head
=NULL; printf("************************動態鏈表實驗***********************\n【輸入動態鏈表】\n");printf("請依次輸入學號 姓名 身高(cm) 體重(kg)(用空格間隔,學號輸入0結束):\n");p2
=p1
=(struct Student
*)malloc(LEN
);scanf("%d %s %f %f",&p1
->ID
,&p1
->name
,&p1
->height
,&p1
->weight
);if(p1
->ID
==0)return(head
);else head
=p1
;while(p1
->ID
!=0){p2
->next
=p1
;p2
=p1
;p2
->BMI
=(float)p2
->weight
/(p2
->height
/100)/(p2
->height
/100);p1
=(struct Student
*)malloc(LEN
);scanf("%d %s %f %f",&p1
->ID
,&p1
->name
,&p1
->height
,&p1
->weight
);}p2
->next
=NULL;return(head
);
}
void output(struct Student
*head
)
{struct Student
*p
;int num
=1;p
=head
;printf("【輸出動態鏈表】\n");printf("|學號\t\t|姓名\t|身高\t|體重\t|BMI\n");while(p
!=NULL){printf("%3d|%08d\t|%s\t|%5.2f\t|%5.2f\t|%lf\n",num
++,p
->ID
,p
->name
,p
->height
,p
->weight
,p
->BMI
);p
=p
->next
;}
}
struct Student
*delate(struct Student
*head
,int stdID
)
{struct Student
*p1
,*p2
;if(head
->ID
==stdID
){p1
=head
->next
;free(head
);return p1
;}for(p1
=head
;p1
!=NULL;p2
=p1
,p1
=p1
->next
){if(p1
->ID
==stdID
){p2
->next
=p1
->next
;free(p1
);return head
; }}return NULL;
}
struct Student
*insert(struct Student
*head
,int stdID
,struct Student
*insertstd
)
{struct Student
*p1
,*p2
,*p
;for(p
=insertstd
;p
->next
!=NULL;p
=p
->next
);if(head
->ID
==stdID
){p
->next
=head
;return insertstd
;}for(p1
=head
;p1
!=NULL;p2
=p1
,p1
=p1
->next
){if(p1
->ID
==stdID
){p2
->next
=insertstd
;p
->next
=p1
;return head
; }}return NULL;
}
int append(struct Student
*head
)
{struct Student
*p
;for(p
=head
;p
->next
!=NULL;p
=p
->next
);p
->next
=input();return 0;
}
struct Student
*isexist(struct Student
*head
,int stdID
)
{struct Student
*p
;for(p
=head
;p
!=NULL;p
=p
->next
){if(p
->ID
==stdID
){return p
;}}return NULL;
}
輸出效果如下圖:
希望本文對您有價值,謝謝閱讀。
總結
以上是生活随笔為你收集整理的C语言实现线性动态(单向)链表【详细步骤】的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。