前面已經對單鏈表做了一些解釋。鏈表在進行循環遍歷時效率不高,但是插入和刪除時優勢明顯。
單鏈表實際上是由節點(Node)組成的,一個鏈表擁有不定數量的節點。而向外暴露的只有一個頭節點(Head),我們對鏈表的所有操作,都是直接或者間接地通過其頭節點來進行的。節點(Node)是由一個需要儲存的對象及對下一個節點的引用組成的。也就是說,節點擁有兩個成員:儲存的對象、對下一個節點的引用。其實應該用數據和地址代替前面的對象和引用的。
單鏈表的結構示意圖(包括空的單鏈表):
那么大家可能清楚了,為什么說有了頭節點就可以操作所有節點。因為有連續不斷的引用嘛!那么在鏈表里的屬性大概就只有兩個了:頭節點和節點數量。當然,根據需要,我們通常需要更多的屬性。
下面用C語言簡單寫一個單鏈表,並完成初始化,創建鏈表與鏈表遍歷。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int ElemType; /* ElemType類型根據實際情況而定,這里假設為int */
/* 定義單鏈表結點類型 */
typedef struct Node{
ElemType element;
struct Node *next;
}Node;
/* 1.初始化線性表,即置單鏈表的表頭指針為空 */
void initList(Node **pNode)
{
*pNode = NULL;
printf("initList函數執行,初始化成功\n");
}
/* 2.創建線性表,此函數輸入負數終止讀取數據*/
Node *creatList(Node *pHead)
{
Node *p1;
Node *p2;
p1=p2=(Node *)malloc(sizeof(Node)); //申請新節點
if(p1 == NULL || p2 ==NULL)
{
printf("內存分配失敗\n");
exit(0);
}
memset(p1,0,sizeof(Node));
scanf("%d",&p1->element); //輸入新節點
p1->next = NULL; //新節點的指針置為空
while(p1->element > 0) //輸入的值大於0則繼續,直到輸入的值為負
{
if(pHead == NULL) //空表,接入表頭
{
pHead = p1;
}
else
{
p2->next = p1; //非空表,接入表尾
}
p2 = p1;
p1=(Node *)malloc(sizeof(Node)); //再重申請一個節點
if(p1 == NULL || p2 ==NULL)
{
printf("內存分配失敗\n");
exit(0);
}
memset(p1,0,sizeof(Node));
scanf("%d",&p1->element);
p1->next = NULL;
}
printf("creatList函數執行,鏈表創建成功\n");
return pHead; //返回鏈表的頭指針
}
/* 3.打印鏈表,鏈表的遍歷*/
void printList(Node *pHead)
{
if(NULL == pHead) //鏈表為空
{
printf("PrintList函數執行,鏈表為空\n");
}
else
{
while(NULL != pHead)
{
printf("%d ",pHead->element);
pHead = pHead->next;
}
printf("\n");
}
}
int main()
{
Node *pList = NULL;
int length = 0;
ElemType posElem;
initList(&pList); //鏈表初始化
printList(pList); //遍歷鏈表,打印鏈表
printf("請為鏈表輸入節點值,輸入負數退出 \n");
pList=creatList(pList); //創建鏈表
printList(pList);
}
鏈表是由不定數量的節點連接(通過相互之間的引用)起來的,由於這種關系,在鏈表里我們只定義了頭節點和節點數量。節點是由存儲的對象及對下一個“節點”的引用封裝而成。
