Ⅰ c語言中如何實現用文件保存一個動態的鏈表
隨便說說
你可以
鏈表
的每一個結點,保存為一行.或者有一個特殊的符號來分割不同的結點,如果結點內有不同意義的數據,也可以用特殊的符號來分割,
這里要說明
因為c語言支持的只有流試文件
所以在文件存儲鏈表的時候只能存儲
單向鏈表
Ⅱ c語言中創建動態鏈表
給你些資料吧~仔細看,看完就明白鏈表了
10.7 用指針處理鏈表
10.7.1鏈標概述
鏈表是一種常見的重要的數據結構.它是動態地進行存儲分配的一種結構.我們知道,用數組存放數據時,
必須事先定義固定的長度(即元素個數).比如,有的班級有100人,而有的班只有30人,如果要用同一個數組先後存放不同班級的學生數據,則必須定義長度為100的數組.如果事先難以確定一個班的最多人數,則必須把數組定得足夠大,以能存放任何班級的學生數據.顯然這將會浪費內存.鏈表則沒有這種缺點,它根據需要開辟內存單元.圖10.11表示最簡單的一種鏈表(單向鏈表)的結構.鏈表有一個"頭指針"變數,圖中以head表示,它存放一個地址.
該地址指向一個元素.鏈表中每一個元素稱為"結點",每個結點都應包括兩個部分:一為用戶需要用的實際數據,二為下一個結點的地址.課以看出,head指向第一個元素;第一個元素又指向第二個元素;……,直到最後一個元素,該元素不再指向其它元素,它稱為'表尾",它的地址部分放一個"NULL"(表示"空地址").鏈表到此結束.
可以看到:鏈表中各元素在內存中可以不是連續存放的.要找某一元素,必須先找到上一個元素,根據它提供的下一元素地址才能找到下一個元素.
如果不提供"頭指針"(head),則整個鏈表都無法訪問.鏈表如同一條鐵鏈一樣,一環扣一環,中間是不能斷開的.打個通俗的比方:幼兒園的老師帶領孩子出來散步,老師牽著第一個小孩的手,第一個小孩的另一隻手牽著第二個孩子,……,這就是一個"鏈",最後一個孩子有一隻手空著,他是"鏈尾".要找這個隊伍,必須先找到老師,然後順序找到每一個孩子.
可以看到,這種鏈表的數據結構,必須利用指針變數才能實現
.即:一個結點中應包含一個指針變數,用它存放下一結點的地址.
前面介紹了結構體變數,它包含若干成員.這些成員可以是數值類型,字元類型,數組類型,也可以是指針類型.這個指針類型可以是指向其它結構體類型數據,也可以指向它所在的結構體類型.例如:
struct student
{int num;
float score;
struct student *next;
next是成員名,它是指針類型的,它指向struct student類型數據(這就是next所在的結構體類型).用這種方法可以建立鏈表.見圖10.12.
其中每一個結點都屬於struct student類型,它的成員next存放下一結點的地址,程序設計人員可以不必具體知道地址值,
只要保證將下一個結點的地址放到前一結點的成員next中即可.
請注意:上面只是定義了一個struct student類型,並未實際分配存儲空間.前面講過,鏈表結構是動態地分配存儲的,即在需要時才開辟一個結點的存儲單元.怎樣動態地開辟和釋放存儲單元呢 C語言編譯系統的庫函數提供了以下有關函數.
1.malloc(size) 在內存的動態存儲區中分配一個長度為size的連續空間.
此函數的值(即"返回值")是一個指針,它的值是該分配域的起始地址.如果此函數未能成功地執行,則返回值為0.
2.calloc(n,size) 在內存的動態區存儲中分配n個長度為size的連續空間.函數返回分配域的起始地址;如果分配不成功,返回0.
3.free(ptr) 釋放由ptr指向的內存區.ptr是最近一次調用ca11或ma11oc函數時返回的值.
上面三個函數中,參數n和size為整型,ptr為字元型指針.
請注意:許多C版本提供的malloc和call0c函數得到的是指向字元型數據的指針.新標准C提供的ma110c和ca11oc函數規定為void*類型.
有了本節所介紹的初步知識,下面就可以對鏈表進行操作了(包括建立鏈表,插入或刪除鏈表中一個結點等).有些概念需要在後面的應用中逐步建立和掌握.
10.7.2建立鏈表
所謂建立鏈表是指從無到有地建立起一個鏈表,即一個一個地輸入各結點數據,並建立起前後相鏈的關系.下面通過一個例子來說明如何建立一個鏈表.
[例10.7]寫一函數建立一個有5名學生數據的單向鏈表.
先考慮實現此要求的演算法(見圖10. 13).
設三個指針變數:head,p1,p2,它們都指向結構體類型數據.先用mal1oc函數開辟一個結點,並使p1,p2指向它.
然後從鍵盤讀人一個學生的數據給pl所指的結點.我們約定學號不會為零,如果輸入的學號為0,則表示建立鏈表的過程完成,該結點不應連接到鏈表中.先使head的值為NULL(即等於0),這是鏈表為"空"時的情況(即head不指向任何結點,鏈表中無結點),以後增加一個結點就使head指向該結點.
如果輸入的pl一>num不等於0,而且輸入的是第一個結點數據(n=1)時,則令head=p1,
即把p1的值賦給head,也就是使head也指向新開辟的結點(圖10.14).P1所指向的新開辟的結點就成為鏈表中第一個結點.然後再開辟另一個結點並使p1指向它,接著讀入該結點的數據(見圖10.15(a)).如果輸入的p1->num!=0,則應鏈入第2個結點(n=2),由於n!=1,則將p1的值賦給p2-->next,也就是使第一個結點的next成員指向第二個結點(見圖10.15(b)).接著使p2=p1,
也就是使p2指向剛才建立的結點,見圖10.15(c).再開辟一個結點並使pl指向它,並讀入該結點的數據(見圖10.16(a)),在第三次循環中,由於n=3(n!=1),又將pl的值賦給p2一>next,也就是將第3個結點連接到第2個結點之後,並使p2=p1,使p2指向最後一個結點(見圖10.16(b).
再開辟一個新結點,並使pl指向它,
輸入該結點的數據(見圖10.17(a)).由於pl一>num的值為0,不再執行循環,此新結點不應被連接到鏈表中.此時將NULL賦給p2一>next,見圖10.17(b).建立鏈表過程至此結束,pl最後所指的結點未鏈入鏈表中,第3個結點的next成員的值為NULL,它不指向任何結點.雖然pl指向新開辟的結點,但從鏈表中無法找到該結點.
建立鏈表的函數可以如下:
#define NULL 0
#define LEN sizeof(struct student)
struct student
{1ong num;
float score;
struct student *next;
};
int n;
struct student *creat()
/*此函數帶回一個指向鏈表頭的指針*/
{struct student *head;
struct student *p1, *p2;
n=0;
p1=p2=(struct student*)mal1oc(LEN);/*開辟一個新單元*/
scanf("%ld,%f",&pl一>num,&pl一>score);
head=NULL:
while (pl一>num!=0)
{n=n十1;
if(n==1) head=pl;
else p2一>next=p1;
p2=pl;
pl=(struct student*)malloc(LEN);
scanf("%1d,%f",&p1-->num,&pl一>score);
}
p2一>next=NULL;
return(head);
}
請注意:
(1)第一行為#define命令行,令NULL代表0,用它表示"空地址".第二行令LEN代表struct student結構體類型數據的長度,
sizeof是"求位元組數運算符".
(2)第9行定義一個creat函數,它是指針類型,即此函數帶回一個指針值,它指向一個struct student類型數據.實際上此creat函數帶回一個鏈(3)malloc(LEN)的作用是開辟一個長度為LEN的內存區,LEN已定義為sizeof(struct student),即結構體struct student的長度.在一般系統中,malloc帶回的是指向字元型數據的指針.
而p1,p2是指向struct student類型數據的指針變數,二者所指的是不同類型的數據,這是不行的.因此必須用強制類型轉換的方法使之類型一致,在malloc (LEN)之前加了"(struct student*)",它的作用是使malloc返回的指針轉換為指向struct student類型數據的指針.注意"*"號不可省略,否則變成轉換成struct student類型了,而不是指針類型了.
(4)最後一行return後面的參數是head(head已定義為指針變數,指向struct student類型數據).因此函數返回的是head的值,也就是鏈表的頭地址.
(5)n是結點個數.
(6)這個演算法的思路是:讓pl指向新開的結點,p2指向鏈表中最後一個結點,把pl所指的結點連接在p2所指的結點後面,用"p2一>next=pl"來實現.
我們對建立鏈表過程作了比較詳細的介紹,
讀者如果對建立鏈表的過程比較清楚的話,對下面介紹的刪除和插入過程也就比較容易理解了.
10.7.3輸出鏈麥
將鏈表中各結點的數據依次輸出.這個問題比較容易處理.首先要知道鏈表頭元素的地址,也就是要知道head的值.然後設一個指針變數p,先指向第一個結點,輸出p所指的結點,然後使p後移一個結點,再輸出.直到鏈表的尾結點.
「例10.8]寫出輸出鏈表的函數print.
void print(head)
struct student *head;
{struct student *p;
printf("\nNow,These%drecords are:\n",n);
p=head;
if(head!=NULL)
do
{printf("%ld%5.1f\",p一>num,p—>score);
p=p一>next;
}while(p!=NULL);
演算法可用圖10.18表示.
其過程可用圖10.19表示.p先指向第一結點,在輸出完第一個結點之後,p移到圖中p'虛線位置,指向第二個結點.程序中p=p一>next的作用是:將p原來所指向的結點中next的值賦給p,
而p一>next的值就是第二個結點的起始地址.將它賦給p就是使p指向第二個結點.
head的值由實參傳過來,也就是將已有的鏈表的頭指針傳給被調用的函數,在print函數中從head所指的第一個結點出發順序輸出各個結點.
10.7.4 對鏈麥的刪除操作
已有一個鏈表,希望刪除其中某個結點.怎樣考慮此問題的演算法呢,先打個比方:
一隊小孩(A.B.C.D.E)手拉手,如果某一小孩(C)想離隊有事,而隊形仍保持不變.只要將C的手從兩邊脫開,B改為與D拉手即可,見圖10.20.圖10.20(a)是原來的隊伍,圖10.20(b)是c離隊後的隊伍.
與此相仿,從一個鏈表中刪去一個結點,並不是真正從內存中把它抹掉,而是把它從鏈表中分離開來,即改變鏈接關系即可.
[例10.9]寫一函數以刪除指定的結點.
我們以指定的學號作為刪除結點的標志.例如,輸入89103表示要求刪除學號為89103的結點.解題的思路是這樣的:從p指向的第一個結點開始,檢查該結點中的num值是否等於輸入的要求刪除的那個學號.如果相等就將該結點刪除,如不相等,就將p後移一個結點,再如此�下去,直到遇到表尾為止.
可以設兩個指針變數pl和p2,先使pl指向第一個結點(圖10.21(a)).如果要刪除的不是第一個結點,
則使pl後指向下一個結點(將pl一>next賦給pl),在此之前應將pl的值賦給p2,使p2指向剛才檢查過的那個結點,見圖10.21(b).如此一次一次地使p後移,直到找到所要刪除的結點或檢查完全部鏈表都找不到要刪除的結點為止.如果找到某一結點是要刪除的結點,還要區分兩種情況:①要刪的是第一個結點(pl的值等於head的值,如圖10.21(a)那樣),則應將pl一>next賦給head.見圖10.21(c).
這時head指向原來第二個結點.第一個結點雖然仍存在,但它已與鏈表脫離,因為鏈表中沒有一個元素或頭指針指向它.雖然p1還指向它,它仍指向第二個結點,但仍無濟於事,現在鏈表的第一個結點是原來第二個結點,原來第一個結點"丟失".②如果要刪除的不是第一個結點,則將pl一>next賦給p2一>next,見圖10.21(d).p2一>next原來指向pl指向的結點(圖中第二個結點),現在p2一>next改為指向p1一>next所指向的結點
(圖中第三個結點).pl所指向的結點不再是鏈表的一部分.
還需要考慮鏈表是空表(無結點)和鏈表中找不到要刪除的結點的情況.
圖10.22表示解此題的演算法.
刪除結點的函數del如下:
struct student *del(head,num)
struct student *head;
1ong num;
{struct student *p1,*p2;
if(head==NULL) {printf("\nlist null!\n");goto end;}
p1=head;
whi1e (num!=pl一>num&&pl一>next!一NULL)/*pl指向的不是所要找的結點,並且後面還有結點點*/
{p2=p1;pl=pl一>next;}/*後移一個結點*/
if (num==pl一>num) /*找到了*/
{if (n1==head) head=pl一>next;/*若pl指向的是頭結點,把第二個結點地址賦予head*/
e1se p2一>next=pl一>next;/*否則將下一結點地址賦給前一結點地址*\
printf("delete:%ld\n",num);
n=n-1;
}
else printf("%ld not been found!\n",num);/*找不到該結點*/
end:
return(head);
}
函數的類型是指向struct student類型數據的指針,
它的值是鏈表的頭指針.函數參數為head和要刪除的學號num.head的值可能在函數執行過程中被改變(當刪除第一個結點時).
10.7.5對鏈表的插入操作
將一個結點插入到一個已有的鏈表中.設已有的鏈表中各結點中的成員項num(學號)是按學號由小到大順序排列的.
用指針變數p0指向待插入的結點,pl指向第一個結點.見圖10.23(a).
將p0一>num與pl一>num相比較,如果p0一>num>pl一>num,則待插入的結點不應插在pl所指的結點之前.此時將pl後移,並使p2指向剛才pl所指的結點,見圖10.23(b).再將p1一>num與p0一>num比.如果仍然是p0一>num大,則應使pl繼續後移,直到p0一>numnum為止.這時將p0所指的結點插到pl所指結點之前.但是如果p1所指的已是表尾結點,則pl就不應後移了.如果p0一>num比所有結點的num都大,
則應將p0所指的結點插到鏈表末尾.
如果插入的位置既不在第一個結點之前,又不在表尾結點之後,則將p0的值賦給p2一>next,即使p2一>next指向待插入的結點,然後將pl的值賦給p0->next,即使得p0一>next指向pl指向的變數.見圖10.23(c).可以看到,在第一個結點和第二個結點之間已插入了一個新的結點.
如果插入位置為第一結點之前(即pl等於head時),
則將p0賦給head,將p1賦給p0->next.見圖10.23(d).如果要插到表尾之後,應將p0賦給pl一>next,NULL賦給p0一>next,見圖10.23(e).
以上演算法可用圖10.24表示.
[例10. 10]插入結點的函數insert如下.
struct student *insert(head,stud)
struct student *head,*stud:
{struct student *p0,*p1,*p2;
pl=head;/*使pl指向第一個結點*/
p0=stud;/*p0指向要插入的結點*/
if (head==NULL)/*原來是空表*/
{head=p0;p0一>next=NULL;}/*使p0指向的結點作為第一個結點*/
else
{while ((p0一>num>pl一>num)&&(pl一>next!=NULL))
{p2=p1;p1=pl一>next;}/*p2指向剛才pl指向的結點,p1後移一個結點*/
if(p0->numnext=p0;/*插到p2指向的結點之後*/
p0—>next=p1;}
else
{pl一>next=p0;p0一>next=NULL;}}/*插到最後的結點之後*/
n=n+1; /*結點數加1*/
return(head);
}
函數參數是head和stud.stud也是一個指針變數,從實參傳來待插入結點的地址給stud.語句p0=stud的作用是使p0指向待插入的結點.
函數類型是指針類型,函數值是鏈表起始地址head.
將以上建立,輸出,刪除,插入的函數組織在一個程序中,用main函數作主調函數.可以寫出以下main函數.
main()
{struct student *head,stu;
1ong de1_num;
printf("input records:\n");
head=creat(); /*返回頭指針*/
print(head); /*輸出全部結點*/
printf("\ninput the deleted 0number:");
scanf("%ld",&de1_mum);/*輸入要刪除的學號*/
head=del(head,de1_num);/*刪除後的頭地址*/
print(head); /*輸出全部結點*/
prinif("/ninput the inserted record:")/*輸入要插入的記錄*/
scanf("%ld,%f",&stu.num,&stu.score);
head=insert(head,&stu);/*返回地址*/
print(head);
}
此程序運行結果是正確的.
它只刪除一個結點,插入一個結點.但如果想再插入一個結點,重復寫上程序最後四行,即共插入兩個結點.運行結果卻是錯誤的.
input records:(建立鏈表)
89101,90
89103,98
89105,76
0,0
Now,These 3 records are:
89101 90.0
89103 98.0
89105 76.0
inpu the deleted number:
89103 (刪除)
delete:89103
Now,These 2 records are:
89101 90.0 89105 76.0
input the inserted record:89102
90 (插入第一個結點)
Now,These 3 records are:
89101 90.0
89102 90.0
89105 76.0
input the inserted record:89104,99/(插入第二個結點)
Now,The 4 records are:
89101 90.0
89104 99.0
89104 99.0
89104 99.0
...
...
(無終止地輸出89104的結點數據)
請讀者將main與insert函數結合起來考察為什麼會產生以上運行結果.
出現以上結果的原因是:stu是一個有固定地址的變數.第一次把stu結點插入到鏈表中.第二次若再用它來插入第二個結點,就把第一次結點的數據沖掉了.
實際上並沒有開辟兩個結點.讀者可根據insert函數畫出此時鏈表的情況.為了解決這個問題,必須在每插入一個結點時新開辟一個內存區.我們修改main函數,使之能刪除多個結點(直到輸入要刪的學號為0),能插入多個結點(直到輸入要插入的學號為0).
main函數如下:
main()
{struct student *head,*stu;
1ong de1_num;
printf("input records:/n");
head=creat();
print (head);
printf("/ninput the deleted number:");
scanf("%1d",&del_num);
while (de1_num!=0)
{head=del(head,del_num);
print(head);
printf("input the deleted number:");
scanf("%ld",&del_num);
printf("\ninput the inserted record:");
stu=(struct student*)malloc(LEN);
scanf("%1d,%f,",&stu一>num,&stu一>scor);
while (stu一>num!=0)
{head=insert(head,stu):
print(head);
prinif("input the inserted record:");
stu=(struct student*)malloc(LEN);
scanf("%1d,%f,&stu一>num,&stu一>score);
}
}
sum定義為指針變數,在需要插入時先用malloc函數開辟一個內存區,將其起始地址經強制類型轉換後賦給stu,然後輸入此結構體變數中各成員的值.對不同的插入對象,stu的值是不同的,每次指向一個新的結構體變數.在調用insert函數時,實參為head和stu,將已建立的鏈表起始地址傳給insert函數的形參,將stu(既新開辟的單元的地址)傳給形參stud,函數值返回經過插入之後的鏈表的頭指針(地址).
運行情況如下:
input records:
89101,99
89103,87
89105,77
0,0
Now, These 3 records are.
89101 99.0
89103 87.0
89105 77.0
input the deleted number:89103
delete:89103
Now,These 2 records are:
89101 99.0
89105 77.0
input the de1eted number:89105
delete:89105
Now,These l records are:
89101 99.0
input the de1eted number:0
1nput the inserted record:89104,87
NOw,These 2 records are:
89101 99.0
89104 87.0
input the inserted record:89106,65
Now,These 3 records are:
89101 99.0
89104 87.0
89106 65.0
input the inserted record:0,0
對這個程序請讀者仔細消化.
指針的應用領域很寬廣,除了單向鏈表之外,還有環形鏈表,雙向鏈表.此外還有隊列,樹,棧,圖等數據結構.
有關這些問題的演算法可以學習《數據結構>>課程,在此不作詳述.
Ⅲ c語言建立動態鏈表
struct student
{
long no;
char name[10];
int age;
struct student *next;
};
struct student *head = NULL;
void Add(struct student *stu)
{
struct student *p,*q;
if(head == NULL)
head = stu;
else
{
p = head;
while(p != NULL)
{
q = p;
p = p->next;
}
q ->next = stu;
}
}
void Print()
{
struct student *p = head,i = 0;
if(p == NULL) return ;
while(p != NULL)
{
printf("學生 %d\n",i+1);
printf("學號:%ld\n",p->no);
printf("姓名:%s\n",p->name);
printf("年齡:%d\n",p->age);
p = p->next;
i++;
}
}
void Destroy()
{
struct student *p = head,*q;
if(head == NULL) return ;
while(p!= NULL)
{
q = p ->next;
free(p);
p = q;
}
head = NULL;
}
調用:
int main()
{
int i ;
struct student *stu = (struct student*)malloc(sizeof(struct student)*4);
for(i = 0;i < 4;i++)
{
scanf("%ld",&stu[i]->no);
scanf("%s",stu[i]->name);
scanf("%d",&stu[i]->age);
stu->next = NULL;
Add(&stu[i]);
}
Print();
getch();
return 0;
}
Ⅳ c語言動態鏈表問題
那個n是程序運行起來後才由用戶輸入得來的,而在程序沒運行時是未知的。你寫一般的程序,在程序中對已知需要多大的數組則直接定義,如int a[20],你知道你要處理的問題需要定義20個元素的數組就合適了,但是:果你事先不知道該定義多大的數組才合適,你就得如書上所說,用動態開辟合適大小的空間才能恰當的處理問題了。例如你要統計全縣各校各個年級學生的期末總分排名,中心小學五年級有200人,四年級有300人,三年級只有100人。文藝路小學五年級有500人,四年級有350人等。這個程序要適用所有的學校,各校各級人數不等。就要在程序中動態來開辟空間了,這樣多方便啊。你就不會發愁我是開始定義100大小還是300或還是500。
Ⅳ 使用C語言創建一個動態鏈表
可以用頭插法或尾插法
(下面用尾插法)
思想為:讓你輸入一串字元串,為每個字元創建一個節點,添加到鏈表的後面.直到輸入的字元為@為止.
#include<stdio.h>
#include<malloc.h>
typedefchardatatype;
typedefstructnode
{
datatypedata;
structnode*next;
}linklist;
linklist*p,*q,*head;
main()
{
charc;
head=(linklist*)malloc(sizeof(linklist));
head->next=null;
p=head;
c=getchar();
while(c!='@')
{
q=(linklist*)malloc(sizeof(linklist));
q->data=c;
q->next=null;
p->next=q;
p=p->next;
c=getchar();
}
}
可以在main()最後加上
for(p=head->next;p!=null;p=p->next)
{
printf("%5c",p->data);
}
來測試結果,本人已經tc2.0下面測試通過.
Ⅵ 求寫C語言 創建鏈表實例子。要最基本的 包括注釋。
題目:創建固定長度的單向鏈表
程序分析:鏈表是動態分配存儲空間的鏈式存儲結構,
其包括一個「頭指針」變數,其中第0個結點稱為整個鏈表的頭結點,頭結點中存放一個地址,該地址指向一個元素,頭結點一般不存放具體數據,只是存放第一個結點的地址。
鏈表中每一個元素稱為「結點」,每個結點都由兩部分組成:存放數據元素的數據域和存儲直接後繼存儲位置的指針域。指針域中存儲的即是鏈表的下一個結點存儲位置,是一個指針。多個結點鏈接成一個鏈表。
最後一個結點的指針域設置為空(NULL),作為鏈表的結束標志,表示它沒有後繼結點。
使用結構體變數作為鏈表中的結點,因為結構體變數成員可以是數值類型,字元類型,數組類型,也可以是指針類型,這樣就可以使用指針類型成員來存放下一個結點的地址,使其它類型成員存放數據信息。
在創建列表時要動態為鏈表分配空間,C語言的庫函數提供了幾種函數實現動態開辟存儲單元。
malloc()函數實現動態開辟存儲單元:
malloc函數原型為:void *malloc(unsigned int size);
其作用是在內存的動態存儲區中分配一個長度為size的連續空間,函數返回值是一個指向分配域起始地址的指針(類型為void)。如果分配空間失敗(如,內存空間不足),則返回空間指針(NULL)
#include<stdio.h>
#include<malloc.h>
structLNode
{
intdata;
structLNode*next;
};
/*上面只是定義了一個結構體類型,並未實際分配內存空間
只有定義了變數才分配內存空間*/
structLNode*creat(intn)
{
inti;
structLNode*head,*p1,*p2;
/*head用來標記鏈表,p1總是用來指向新分配的內存空間,
p2總是指向尾結點,並通過p2來鏈入新分配的結點*/
inta;
head=NULL;
for(i=1;i<=n;i++)
{
p1=(structLNode*)malloc(sizeof(structLNode));
/*動態分配內存空間,並數據轉換為(structLNode)類型*/
printf("請輸入鏈表中的第%d個數:",i);
scanf("%d",&a);
p1->data=a;
if(head==NULL)/*指定鏈表的頭指針*/
{
head=p1;
p2=p1;
}
else
{
p2->next=p1;
p2=p1;
}
p2->next=NULL;/*尾結點的後繼指針為NULL(空)*/
}
returnhead;/*返回鏈表的頭指針*/
}
voidmain()
{
intn;
structLNode*q;
printf("請輸入鏈表的長度:/n");
scanf("%d",&n);
q=creat(n);/*鏈表的頭指針(head)來標記整個鏈表*/
printf("/n鏈表中的數據:/n");
while(q)/*直到結點q為NULL結束循環*/
{
printf("%d",q->data);/*輸出結點中的值*/
q=q->next;/*指向下一個結點*/
}
}
Ⅶ C語言如何用動態鏈表儲存數據
單鏈表,雙鏈表,堆 都可以,不過看您要存儲什麼數據 以單鏈表為例: 定義一個節點結構 typedef struct LNode{ ElementType date; struct Lnode *next; }Lnode; 然後用malloc開辟需要的節點空間,把數據存進去就可以了 p = (Lnode) malloc (sizeof(Lnode)); //開辟一個節點,p為所開辟空間的指針 至於查找,從頭節點開始q = p->next ;一個個查就行了。
Ⅷ c語言,建立動態鏈表,大神幫我解釋下括弧部分每一句是什麼作用。
給題主完整講述下creat函數吧
structStudent*creat(){
structStudent*head;/*定義head構體指針,代表頭結點*/
structStudent*p1,*p2;/*定義p1、p2兩個結構體指針*/
n=0;/*計數器,統計節點數量*/
p1=p2=(structStudent*)malloc(LEN);/*申請一個結構體空間,p1、p2均指向它*/
scanf("%d,%f",&p1->num,&p1->score);/*為結構體輸入內容*/
head=NULL;/*頭結點先指向空*/
/*循環插入新節點,並輸入內容。當num變數輸入0時結束*/
while(p1->num!=0){
n=n1+1;/*元素個數+1*/
if(n==1)/*第1個元素時,將頭結點指向p1*/
head=p1;
else/*不是第1個元素時*/
p2->next=p1;/*p2的next指向p1,以形成連接。注意此處循環至少執行過1次,所以p2是前一個節點,p1是上次循環插入的節點*/
p2=p1;/*將p2向後移一位,即指向上次循環插入的節點*/
p1=(structStudent*)malloc(LEN);/*新插入一個節點,p1指向它*/
scanf("%d,%f",&p1->num,&p1->score);/*為新節點輸入內容*/
/*注意此時,在下一次循環中,p1新節點會與p2節點連接,*/
}
p2-next=NULL;/*循環結束時,p2即為最後一個節點,所以p2的next設置為空*/
}
Ⅸ c語言 建立一個鏈表,實現增刪改查
下面是以前寫的一個關於鏈表的綜合操作,你可以看看,應該可以滿足你的要求。
/********************************************************************
created: 2009/09/15
created: 16:9:2009 17:20
filename: E:\dd\lianbiao\lianbiao.cpp
author:
purpose: 一個win32 的控制台程序
實現單項鏈表的數據刪除、插入、排序等功能
*********************************************************************/
#include <stdio.h>
#include "windows.h"
#include "malloc.h"
#define LEN sizeof(struct student)
#define NULL 0
#define N 5 //N為所要創建的鏈表的長度
int n = 0; //定義全局變數n,表示鏈表的節點個數
/*******************************************************************
Author/data: /2009/09/15
Description: 聲明一個結構體作為鏈表的節點.
tip: student 只是一個標簽,是不能聲明變數的
*********************************************************************/
struct student
{
int num;
float cj;
struct student *Pnext;
};
/*******************************************************************
Author/data: /2009/09/15
Description: 創建一個動態鏈表
參數: 返回鏈表的第一個節點的地址
x 為鏈表的長度
*********************************************************************/
struct student *pa(int x)
{
struct student *head;
struct student *p1,*p2;
// n = 0;
p1 = p2 = (struct student *)malloc(LEN); //開辟一個結構體內存
fflush(stdin); // 清除緩沖區數據 避免直接讀入緩沖區數據
scanf("%d,%f",&p1->num,&p1->cj);
head = NULL;
while(p1->Pnext != NULL)
{
n = n+1;
if(n == 1)
{
head = p1; // 鏈表的頭地址
}
else
{
p2->Pnext = p1; //鏈接鏈表數據
}
/* 判斷是否最後一個 */
if(n >= x)
{
p1->Pnext = NULL;
}
else
{
p2 = p1;
p1 = (struct student *)malloc(LEN);
fflush(stdin);
scanf("%d,%f",&p1->num,&p1->cj);
}
}
return(head);
}
/*******************************************************************
Author/data: /2009/09/15
Description: 輸出一個鏈表
參數: head為第一個節點的地址
*********************************************************************/
void print(struct student *head)
{
struct student *p;
int i = 0;
printf("\nNow,These %d records are:\n",n);
p = head;
if(head != NULL) // 如果鏈表不是空的,則進行數據輸出
{
do
{
printf("%d\t",i++);
printf("%5d %5.1f\n",p->num,p->cj); // 輸出鏈表數據
p = p->Pnext;
}while(p != NULL);
}
}
/*******************************************************************
Author/data: /2009/09/16
Description: 釋放動態鏈表的地址空間
參數: 鏈表的頭地址head
無返回值
*********************************************************************/
void freelinkspace(struct student *head)
{
struct student Ltemp;
Ltemp.Pnext = head->Pnext; // Ltemp 用來存放->next,避免空間被
// 釋放後,找不到下一個結點的地址
while(head->Pnext != NULL) // 判斷是否已經空間釋放到最後一個
{
free(head);
head = Ltemp.Pnext;
Ltemp.Pnext = head->Pnext;
}
free(head); // 釋放最後一個結點空間
}
/*******************************************************************
Author/data: /2009/09/15
Description: 刪除鏈表鏈表中的一個結點
參數: head 為第一個節點的地址
num 為要刪除結點的序號(head->num)
*********************************************************************/
struct student *del(struct student *head,int num)
{
struct student *p1,*p2;
p1 = head;
while(p1->num!=num && p1->Pnext!=NULL) // 尋找要刪除的結點
{
p2 = p1; // p2 存放刪除結點的前一個結點地址
p1 = p1->Pnext; // p1 存放要刪除的結點
}
if(num == p1->num) // 是否找到要刪除結點
{
if(p1 == head) // 刪除的是第一個結點
{
head = p1->Pnext;
}
else if(p1->Pnext == NULL) // 刪除的是最後一個結點
{
p2->Pnext = NULL;
}
else // 刪除中間的結點
{
p2->Pnext = p1->Pnext;
p1->Pnext = NULL;
}
printf("delete: %d\n",num);
n = n-1; // 鏈表長度 - 1
}
else
{
printf("%d not been found! \n",num);
}
delete(p1);
return(head);
}
/*******************************************************************
Author/data: /2009/09/16
Description: 添加一個結點到鏈表中
參數: head 為第一個結點的地址指針
stud 為要插入的結點的地址指針
*********************************************************************/
struct student *insert(struct student *head,struct student *stud)
{
struct student *p0,*p1,*p2;
p0 = stud;
p1 = head;
while(p0->num>p1->num && p1->Pnext!=NULL) // 找到添加結點的位置
{
p2 = p1; // p2 存放要添加的前一個結點的地址
p1 = p1->Pnext; // p1 存放要添加的後一個結點的地址
}
if(p0->num<=p1->num && p1->Pnext!=NULL)
{
if(p1 == head) // 添加結點到第一個位置
{
p0->Pnext = p1;
head = p0;
}
else
{
p2->Pnext = p0;
p0->Pnext = p1;
}
}
else // 添加結點到最後一個位置
{
p1->Pnext = p0;
p0->Pnext = NULL;
}
n = n+1; // 結點數目 + 1
return(head);
}
/*******************************************************************
Author/data: /2009/09/16
Description: 鏈表的重新排序===按照.num(不能重復)的大小從小到大排
列鏈表數據
參數: head 接收鏈表第一個節點的地址指針
返回值為新生成鏈表的第一個節點的地址指針
*********************************************************************/
struct student *linkpaix(struct student *head)
{
struct student *stemp,*ltemp,*shead,*head_h; /* */
struct student *p,*q; /* 申請兩個鏈表指針,用來儲存鏈表交換過
程的中間值 */
head_h = head;
ltemp = head;
p = (struct student *) malloc(LEN);
q = (struct student *) malloc(LEN); /* 為p,q開辟動態存儲空間 */
/* -==== 先將鏈表的第一個數據與其他數據比較 ====- */
while(head->Pnext != NULL)
{
shead = head;
head = head->Pnext;
if(ltemp->num > head->num)
{
if(ltemp == shead)
{
ltemp ->Pnext = head ->Pnext;
head ->Pnext = ltemp;
}
else
{
p->Pnext = head ->Pnext;
q->Pnext = ltemp ->Pnext;
head ->Pnext = q->Pnext;
shead ->Pnext = ltemp;
ltemp ->Pnext = p->Pnext;
}
head_h = head;
head = ltemp;
ltemp = head_h;
}
}
/* -==== 先將鏈表的第一個數據與其他數據比較 ====- */
/* -==== 比較鏈表第一個以外的數據 ====- */
while(ltemp ->Pnext != NULL)
{
stemp = ltemp;
ltemp = ltemp ->Pnext;
head = ltemp;
while(head->Pnext != NULL)
{
shead = head;
head = head->Pnext;
if(ltemp->num > head->num)
{
if(ltemp == shead)
{
p->Pnext = head ->Pnext;
stemp ->Pnext = head;
head ->Pnext = ltemp;
ltemp ->Pnext = p->Pnext;
}
else
{
p->Pnext = head ->Pnext;
q->Pnext = ltemp ->Pnext;
stemp ->Pnext = head;
head ->Pnext = q->Pnext;
shead ->Pnext = ltemp;
ltemp ->Pnext = p->Pnext;
}
head = ltemp;
ltemp = stemp ->Pnext;
}
}
}
/* -==== 比較鏈表第一個以外的數據 ====- */
free(p);
free(q); // 釋放p,q的動態存儲空間
return(head_h);
}
/*******************************************************************
Author/data: /2009/09/15
Description: 主函數
參數:
*********************************************************************/
void main()
{
struct student *phead,*pins; // 定義2個鏈表指針
int delnum, selflog,flog_a = 1,Nf = 1; // 要刪除的對象id
char delflog ; // 刪除標志y/n
char insflog, flog_nx = 'n';
char flog_free ; // 釋放標志
/* === 輸入N個數據 === N 為定值
printf("please input %d numbers:\n",N);
phead = pa(N); // 創建一個動態鏈表,並賦值
print(phead); // 輸出鏈表數據
*/
/* === 輸入Nx個數據 === Nx 為輸入值 === */
int Nx; // Nx 想要輸入的鏈表長度
printf("How long do you want establish? \t");
fflush(stdin);
scanf("%d",&Nx);
/* -== 判斷創建的是否是一個空鏈表 ==- */
while(Nx == 0)
{
printf("您要創建的是一個空鏈表,是否確定?y/n \t");
fflush(stdin);
scanf("%c",&flog_nx);
if(flog_nx == 'n')
{
printf("How long do you want input?\t");
fflush(stdin);
scanf("%d",&Nx);
}
else if(flog_nx == 'y') goto endl;
else
{
printf("wrong input!\n");
printf("How long do you want input?\t");
fflush(stdin);
scanf("%d",&Nx);
}
}
printf("please input %d numbers: ",Nx);
printf("如:1,3 兩個數中間以,隔開\n");
phead = pa(Nx); // 創建一個動態鏈表,並賦值
print(phead); // 輸出鏈表數據
/* -== 鏈表操作 ==- */
while(flog_a)
{
if(phead == NULL) {printf("鏈表已空,無法操作\n"); flog_a = 0; break;}
printf("\n操作\n1:\t插入數據\n2:\t刪除數據\n3:\t排序\n4:\t清屏\n5:\t輸出現在的鏈表數據\n0:\texit\n");
printf("\nPlease input:\t");
fflush(stdin);
if(scanf("%d",&selflog)) // select flog 選擇項
switch(selflog)
{
case 1 :
/* ====== 插入數據到鏈表 ====== */
printf("insert someone? y/n\t");
fflush(stdin);
scanf("%c",&insflog);
while(insflog != 'n')
{
while(insflog != 'y'&& insflog != 'n')
{
printf("wrnong input,please input again. \n");
printf("another one? y/n\t");
fflush(stdin);
scanf("%c",&insflog);
}
printf("please input the date:\n");
pins = (struct student *)malloc(LEN);
fflush(stdin);
scanf("%d,%f",&pins->num,&pins->cj);
phead = insert(phead,pins);
print(phead);
printf("another one? y/n\t");
fflush(stdin);
scanf("%c",&insflog);
while(insflog != 'y'&& insflog != 'n')
{
printf("wrnong input,please input again. \n");
printf("another one? y/n\t");
fflush(stdin);
scanf("%c",&insflog);
}
}
/* ====== 插入數據到鏈表 ====== */
break;
case 2 :
/* ====== 刪除鏈表中的數據 ====== */
printf("del someone? y/n\t");
fflush(stdin);
scanf("%c",&delflog);
while(delflog != 'n' && phead != NULL)
{
while(delflog != 'y'&& delflog != 'n')
{
printf("wrnong input,please input again. \n");
printf("del someone? y/n\t");
fflush(stdin);
scanf("%c",&delflog);
}
printf("please input the student what you want del:\n");
fflush(stdin);
scanf("%d",&delnum);
phead = del(phead,delnum);
print(phead);
printf("another one? y/n\t");
fflush(stdin);
scanf("%c",&delflog);
if((n+1)==0)
{
printf("There is no more num could be del!\n");
break;
}
}
/* ====== 刪除鏈表中的數據 ====== */
break;
case 3 :
/* ====== 排列鏈表數據 ====== */
printf("\n排序之後:");
phead = linkpaix(phead);
print(phead); // 排序該數據鏈表
/* ====== 排列鏈表數據 ====== */
break;
case 4 :// clrscr();
system("cls");
break;
case 5 : print(phead); break;
case 0 : flog_a = 0 ; break; /* 退出 */
default : printf("wrong input\nPlease input again");
break;
}
else printf("非法輸入!\n");
}
endl: while(1)
{
if(Nx == 0)
{
printf("Can't establish the link!\n");
break;
}
printf("\n保留數據?y/n\t"); // 是否釋放地址空間
fflush(stdin);
scanf("%c",&flog_free);
if(flog_free == 'y')
{
break;
}
else if(flog_free == 'n')
{
freelinkspace(phead);
break;
}
else
{
printf("wrong input!\n");
}
}
printf("OVER!\nGOOD LUCK!\n");
}