1. 程式人生 > >一個實用性很廣的C語言連結串列例項 [轉]

一個實用性很廣的C語言連結串列例項 [轉]

連結串列的c語言實現(一)

準備:動態記憶體分配
一、為什麼用動態記憶體分配
但我們未學習連結串列的時候,如果要儲存數量比較多的同類型或同結構的資料的時候,總是使用一個數組。比如說我們要儲存一個班級學生的某科分數,總是定義一個float型(存在0.5分)陣列:
float score[30];
但是,在使用陣列的時候,總有一個問題困擾著我們:陣列應該有多大?
在很多的情況下,你並不能確定要使用多大的陣列,比如上例,你可能並不知道該班級的學生的人數,那麼你就要把陣列定義得足夠大。這樣,你的程式在執行時就申請了固定大小的你認為足夠大的記憶體空間。即使你知道該班級的學生數,但是如果因為某種特殊原因人數有增加或者減少,你又必須重新去修改程式,擴大陣列的儲存範圍。這種分配固定大小的記憶體分配方法稱之為靜態記憶體分配。但是這種記憶體分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的記憶體空間,在少數情況下,當你定義的陣列不夠大時,可能引起下標越界錯誤,甚至導致嚴重後果。
那麼有沒有其它的方法來解決這樣的外呢體呢?有,那就是動態記憶體分配。
所謂動態記憶體分配就是指在程式執行的過程中動態地分配或者回收儲存空間的分配記憶體的方法。動態記憶體分配不象陣列等靜態記憶體分配方法那樣需要預先分配儲存空間,而是由系統根據程式的需要即時分配,且分配的大小就是程式要求的大小。從以上動、靜態記憶體分配比較可以知道動態記憶體分配相對於景泰記憶體分配的特點:
1、不需要預先分配儲存空間;
2、分配的空間可以根據程式的需要擴大或縮小。
二、如何實現動態記憶體分配及其管理
要實現根據程式的需要動態分配儲存空間,就必須用到以下幾個

函式
1、malloc函式
malloc函式的原型為:
void *malloc (unsigned int size)
其作用是在記憶體的動態儲存區中分配一個長度為size的連續空間。其引數是一個無符號整形數,返回值是一個指向所分配的連續儲存域的起始地址的指標。還有一點必須注意的是,當函式未能成功分配儲存空間(如記憶體不足)就會返回一個NULL指標。所以在呼叫該函式時應該檢測返回值是否為NULL並執行相應的操作。
下例
是一個動態分配的程式:

#include 
#include 
main()
{
int count,*array; /*count是一個計數器,array是一個整型指標,也可以理解為指向一個整型陣列的首地址*/
if((array(int *) malloc(10*sizeof(int)))==NULL)
{
printf("不能成功分配儲存空間。");
exit(1);
}
for (count=0;count〈10;count++) /*給陣列賦值*/
array[count]=count;
for(count=0;count〈10;count++) /*列印陣列元素*/
printf("%2d",array[count]);
}


上例中動態分配了10個整型儲存區域,然後進行賦值並列印。例中if((array(int *) malloc(10*sizeof(int)))==NULL)語句可以分為以下幾步:
1)分配10個整型的連續儲存空間,並返回一個指向其起始地址的整型指標
2)把此整型指標地址賦給array
3)檢測返回值是否為NULL
2、free函式
由於記憶體區域總是有限的,不能不限制地分配下去,而且一個程式要儘量節省資源,所以當所分配的記憶體區域不用時,就要釋放它,以便其它的變數或者程式使用。這時我們就要用到free函式
函式原型是:
void free(void *p)
作用是釋放指標p所指向的記憶體區。
其引數p必須是先前呼叫malloc

函式或calloc函式(另一個動態分配儲存區域的函式)時返回的指標。給free函式傳遞其它的值很可能造成宕機或其它災難性的後果。
注意:這裡重要的是指標的值,而不是用來申請動態記憶體的指標本身。例:
int *p1,*p2;
p1=malloc(10*sizeof(int));
p2=p1;
……
free(p2) /*或者free(p2)*/
malloc返回值賦給p1,又把p1的值賦給p2,所以此時p1,p2都可作為free函式的引數。
malloc函式是對儲存區域進行分配的。
free函式是釋放已經不用的記憶體區域的。
所以由這兩個函式就可以實現對記憶體區域進行動態分配並進行簡單的管理了。

一、單鏈表的建立
有了動態記憶體分配的基礎,要實現連結串列就不難了。
所謂連結串列,就是用一組任意的儲存單元儲存線性表元素的一種資料結構
連結串列又分為單鏈表、雙向連結串列和迴圈連結串列等。我們先講講單鏈表。
所謂單鏈表,是指資料接點是單向排列的。一個單鏈表結點,其結構型別分為兩部分:
1、資料域:用來儲存本身資料
2、鏈域或稱為指標域:用來儲存下一個結點地址或者說指向其直接後繼的指標
例:
typedef struct node
{
char name[20];
struct node *link;
}stud;
這樣就定義了一個單鏈表的結構,其中char name[20]是一個用來儲存姓名的字元型陣列,指標*link是一個用來儲存其直接後繼的指標
定義好了連結串列的結構之後,只要在程式執行的時候愛資料域中儲存適當的資料,如有後繼結點,則把鏈域指向其直接後繼,若沒有,則置為NULL。
下面就來看一個建立帶表頭(若未說明,以下所指連結串列均帶表頭)的單鏈表的完整程式。

#include <stdio.h>
#include <malloc.h> /*包含動態記憶體分配函式的標頭檔案*/
#define N 10 /*N為人數*/ 
typedef struct node
{
char name[20];
struct node *link;
}stud;

stud * creat(int n) /*建立單鏈表的函式,形參n為人數*/
{
stud *p,*h,*s; /* *h儲存表頭結點的指標,*p指向當前結點的前一個結點,*s指向當前結點*/
int i; /*計數器*/
if((h=(stud *)malloc(sizeof(stud)))==NULL) /*分配空間並檢測*/
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0'; /*把表頭結點的資料域置空*/
h->link=NULL; /*把表頭結點的鏈域置空*/
p=h; /*p指向表頭結點*/
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL) /*分配新儲存空間並檢測*/
{
printf("不能分配記憶體空間!");
exit(0);
}
p->link=s; /*把s的地址賦給p所指向的結點的鏈域,這樣就把p和s所指向的結點連線起來了*/
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name); /*在當前結點s的資料域中儲存姓名*/
s->link=NULL;
p=s;
}
return(h);
}

main()
{
int number; /*儲存人數的變數*/
stud *head; /*head是儲存單鏈表的表頭結點地址的指標*/
number=N;
head=creat(number); /*把所新建的單鏈表表頭地址賦給head*/
}

這樣就寫好了一個可以建立包含N個人姓名的單鏈表了。
寫動態記憶體分配的程式應注意,請儘量對分配是否成功進行檢測。

二、單鏈表的基本運算
建立了一個單鏈表之後,如果要進行一些如插入、刪除等操作該怎麼辦?所以還須掌握一些單鏈表的基本演算法,來實現這些操作。單鏈表的基本運算包括:查詢、插入和刪除。下面我們就一一介紹這三種基本運算的演算法,並結合我們建立單鏈表的例子寫出相應的程式。
1、查詢
對單鏈表進行查詢的思路為:對單鏈表的結點依次掃描,檢測其資料域是否是我們所要查好的值,若是返回該結點的指標,否則返回NULL。
因為在單鏈表的鏈域中包含了後繼結點的儲存地址,所以當我們實現的時候,只要知道該單鏈表的頭指標,即可依次對每個結點的資料域進行檢測。
以下是應用查詢演算法的一個例子:

</pre><p> </p><pre class="cpp" name="code">#include <stdio.h>
#include <malloc.h>
#include <string.h> /*包含一些字串處理函式的標頭檔案*/
#define N 10

typedef struct node
{
char name[20];
struct node *link;
}stud;

stud * creat(int n) /*建立連結串列的函式*/
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->link=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->link=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->link=NULL;
p=s;
}
return(h);
}

stud * search(stud *h,char *x) /*查詢連結串列的函式,其中h指標是連結串列的表頭指標,x指標是要查詢的人的姓名*/
{
stud *p; /*當前指標,指向要與所查詢的姓名比較的結點*/
char *y; /*儲存結點資料域內姓名的指標*/
p=h->link;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0) /*把資料域裡的姓名與所要查詢的姓名比較,若相同則返回0,即條件成立*/
return(p); /*返回與所要查詢結點的地址*/
else p=p->link;
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

main()
{
int number;
char fullname[20];
stud *head,*searchpoint; /*head是表頭指標,searchpoint是儲存符合條件的結點地址的指標*/
number=N;
head=creat(number);
printf("請輸入你要查詢的人的姓名:");
scanf("%s",fullname);
searchpoint=search(head,fullname); /*呼叫查詢函式,並把結果賦給searchpoint指標*/
}

2、插入(後插)
假設在一個單鏈表中存在2個連續結點p、q(其中p為q的直接前驅),若我們需要在p、q之間插入一個新結點s,那麼我們必須先為s分配空間並賦值,然後使p的鏈域儲存s的地址,s的鏈域儲存q的地址即可。(p->link=s;s->link=q),這樣就完成了插入操作。
下例是應用插入演算法的一個例子:

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define N 10

typedef struct node
{
char name[20];
struct node *link;
}stud;

stud * creat(int n) /*建立單鏈表的函式*/
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->link=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->link=s;
printf("請輸入第%d個人的姓名:",i+1);
scanf("%s",s->name);
s->link=NULL;
p=s;
}
return(h);
}

stud * search(stud *h,char *x) /*查詢函式*/
{
stud *p;
char *y;
p=h->link;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->link;
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

void insert(stud *p) /*插入函式,在指標p後插入*/
{
char stuname[20];
stud *s; /*指標s是儲存新結點地址的*/
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
printf("請輸入你要插入的人的姓名:");
scanf("%s",stuname);
strcpy(s->name,stuname); /*把指標stuname所指向的陣列元素拷貝給新結點的資料域*/
s->link=p->link; /*把新結點的鏈域指向原來p結點的後繼結點*/
p->link=s; /*p結點的鏈域指向新結點*/
}

main()
{
int number;
char fullname[20]; /*儲存輸入的要查詢的人的姓名*/
stud *head,*searchpoint;
number=N;
head=creat(number); /*建立新連結串列並返回表頭指標*/
printf("請輸入你要查詢的人的姓名:");
scanf("%s",fullname);
searchpoint=search(head,fullname); /*查詢並返回查詢到的結點指標*/
insert(searchpoint); /*呼叫插入函式*/
}

3、刪除
假如我們已經知道了要刪除的結點p的位置,那麼要刪除p結點時只要令p結點的前驅結點的鏈域由儲存p結點的地址該為儲存p的後繼結點的地址,並回收p結點即可。
以下便是應用刪除演算法的例項:

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define N 10

typedef struct node
{
char name[20];
struct node *link;
}stud;

stud * creat(int n) /*建立新的連結串列的函式*/
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->link=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->link=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->link=NULL;
p=s;
}
return(h);
}

stud * search(stud *h,char *x) /*查詢函式*/
{
stud *p;
char *y;
p=h->link;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->link;
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

stud * search2(stud *h,char *x) /*另一個查詢函式,返回的是上一個查詢函式的直接前驅結點的指標,*/
/*h為表頭指標,x為指向要查詢的姓名的指標*/
/*其實此函式的演算法與上面的查詢演算法是一樣的,只是多了一個指標s,並且s總是指向指標p所指向的結點的直接前驅,*/
/*結果返回s即是要查詢的結點的前一個結點*/
{
stud *p,*s;
char *y;
p=h->link;
s=h;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0)
return(s);
else
{
p=p->link;
s=s->link;
}
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

void del(stud *x,stud *y) /*刪除函式,其中y為要刪除的結點的指標,x為要刪除的結點的前一個結點的指標*/
{
stud *s;
s=y;
x->link=y->link;
free(s);
}

main()
{
int number;
char fullname[20];
stud *head,*searchpoint,*forepoint;
number=N;
head=creat(number);
printf("請輸入你要刪除的人的姓名:");
scanf("%s",fullname);
searchpoint=search(head,fullname);
forepoint=search2(head,fullname);
del(forepoint,searchpoint);

一、迴圈連結串列
迴圈連結串列是與單鏈表一樣,是一種鏈式的儲存結構,所不同的是,迴圈連結串列的最後一個結點的指標是指向該迴圈連結串列的第一個結點或者表頭結點,從而構成一個環形的鏈。
迴圈連結串列的運算與單鏈表的運算基本一致。所不同的有以下幾點:
1、在建立一個迴圈連結串列時,必須使其最後一個結點的指標指向表頭結點,而不是象單鏈表那樣置為NULL。此種情況還使用於在最後一個結點後插入一個新的結點。
2、在判斷是否到表尾時,是判斷該結點鏈域的值是否是表頭結點,當鏈域值等於表頭指標時,說明已到表尾。而非象單鏈表那樣判斷鏈域值是否為NULL。

二、雙向連結串列
雙向連結串列其實是單鏈表的改進。
當我們對單鏈表進行操作時,有時你要對某個結點的直接前驅進行操作時,又必須從表頭開始查詢。這是由單鏈表結點的結構所限制的。因為單鏈表每個結點只有一個儲存直接後繼結點地址的鏈域,那麼能不能定義一個既有儲存直接後繼結點地址的鏈域,又有儲存直接前驅結點地址的鏈域的這樣一個雙鏈域結點結構呢?這就是雙向連結串列。
在雙向連結串列中,結點除含有資料域外,還有兩個鏈域,一個儲存直接後繼結點地址,一般稱之為右鏈域;一個儲存直接前驅結點地址,一般稱之為左鏈域。在c語言中雙向連結串列結點型別可以定義為:
typedef struct node
{
int data; /*資料域*/
struct node *llink,*rlink; /*鏈域,*llink是左鏈域指標,*rlink是右鏈域指標*/
}JD;
當然,也可以把一個雙向連結串列構建成一個雙向迴圈連結串列。
雙向連結串列與單向連結串列一樣,也有三種基本運算:查詢、插入和刪除。

雙向連結串列的基本運算:
1、查詢
假若我們要在一個帶表頭的雙向迴圈連結串列中查詢資料域為一特定值的某個結點時,我們同樣從表頭結點往後依次比較各結點資料域的值,若正是該特定值,則返回指向結點的指標,否則繼續往後查,直到表尾。
下例就是應用雙向迴圈連結串列查詢演算法的一個程式。

#include <stdio.h>
#include <malloc.h>
#define N 10

typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;

stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->rlink=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}

stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->rlink;
}
printf("沒有查詢到該資料!");
}

void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("資料資訊為:\n");
while(p!=h)
{
printf("%s ",&*(p->name));
p=p->rlink;
}
printf("\n");
}

main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
clrscr();
head=creat(number);
print(head);
printf("請輸入你要查詢的人的姓名:");
scanf("%s",studname);
searchpoint=search(head,studname);
printf("你所要查詢的人的姓名是:%s",*&searchpoint->name);
}

2、插入
對於雙向迴圈連結串列,我們現在可以隨意地在某已知結點p前或者p後插入一個新的結點。
假若s,p,q是連續三個結點的指標,若我們要在p前插入一個新結點r,則只需把s的右鏈域指標指向r,r的左鏈域指標指向s,r的右鏈域指標指向p,p的左鏈域指標指向r即可。
在p,q之間插入原理也一樣。
下面就是一個應用雙向迴圈連結串列插入演算法的例子:

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define N 10

typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;

stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->rlink=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}

stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->rlink;
}
printf("沒有查詢到該資料!");
}

void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("資料資訊為:\n");
while(p!=h)
{
printf("%s ",&*(p->name));
p=p->rlink;
}
printf("\n");
}

void insert(stud *p)
{
char stuname[20];
stud *s;
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
printf("請輸入你要插入的人的姓名:");
scanf("%s",stuname);
strcpy(s->name,stuname);
s->rlink=p->rlink;
p->rlink=s;
s->llink=p;
(s->rlink)->llink=s;
}

main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
clrscr();
head=creat(number);
print(head);
printf("請輸入你要查詢的人的姓名:");
scanf("%s",studname);
searchpoint=search(head,studname);
printf("你所要查詢的人的姓名是:%s\n",*&searchpoint->name);
insert(searchpoint);
print(head);
}

3、刪除
刪除某個結點,其實就是插入某個結點的逆操作。還是對於雙向迴圈連結串列,要在連續的三個結點s,p,q中刪除p結點,只需把s的右鏈域指標指向q,q的左鏈域指標指向s,並收回p結點就完成了。
下面就是一個應用雙向迴圈連結串列刪除演算法的例子:

#include 
#include 
#include 
#define N 10


typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;


stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i〈n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p-〉rlink=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}


stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->rlink;
}
printf("沒有查詢到該資料!");
}


void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("資料資訊為:\n");
while(p!=h)
{
printf("%s ",&*(p->name));
p=p->rlink;
}
printf("\n");
}


void del(stud *p)
{
(p->rlink)->llink=p->llink;
(p->llink)->rlink=p->rlink;
free (p);
}


main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
clrscr();
head=creat(number);
print(head);
printf("請輸入你要查詢的人的姓名:");
scanf("%s",studname);
searchpoint=search(head,studname);
printf("你所要查詢的人的姓名是:%s\n",*&searchpoint->name);
del(searchpoint);
print(head);
}

在這裡列舉了一個應用單鏈表基本演算法的綜合程式,雙向連結串列和迴圈連結串列的綜合程式大家可以自己去試一試。

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define N 10

typedef struct node
{
char name[20];
struct node *link;
}stud;

stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
h->name[0]='\0';
h->link=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
p->link=s;
printf("請輸入第%d個人的姓名",i+1);
scanf("%s",s->name);
s->link=NULL;
p=s;
}
return(h);
}

stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->link;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->link;
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

stud * search2(stud *h,char *x)
{
stud *p,*s;
char *y;
p=h->link;
s=h;
while(p!=NULL)
{
y=p->name;
if(strcmp(y,x)==0)
return(s);
else
{
p=p->link;
s=s->link;
}
}
if(p==NULL)
printf("沒有查詢到該資料!");
}

void insert(stud *p)
{
char stuname[20];
stud *s;
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配記憶體空間!");
exit(0);
}
printf("\n請輸入你要插入的人的姓名:");
scanf("%s",stuname);
strcpy(s->name,stuname);
s->link=p->link;
p->link=s;
}

void del(stud *x,stud *y)
{
stud *s;
s=y;
x->link=y->link;
free(s);
}

void print(stud *h)
{
stud *p;
p=h->link;
printf("資料資訊為:\n");
while(p!=NULL)
{
printf("%s ",&*(p->name));
p=p->link;
}
}

void quit()
{
exit(0);
}

void menu(void)
{
clrscr();
printf("\t\t\t單鏈表C語言實現例項\n");
printf("\t\t|————————————————|\n");
printf("\t\t| |\n");
printf("\t\t| [1] 建 立 新 表 |\n");
printf("\t\t| [2] 查 找 數 據 |\n");
printf("\t\t| [3] 插 入 數 據 |\n");
printf("\t\t| [4] 刪 除 數 據 |\n");
printf("\t\t| [5] 打 印 數 據 |\n");
printf("\t\t| [6] 退 出 |\n");
printf("\t\t| |\n");
printf("\t\t| 如未建立新表,請先建立! |\n");
printf("\t\t| |\n");
printf("\t\t|————————————————|\n");
printf("\t\t 請輸入你的選項(1-6):");
}

main()
{
int choose;
stud *head,*searchpoint,*forepoint;
char fullname[20];


while(1)
{
menu();
scanf("%d",&choose);
switch(choose)
{
case 1:head=creat(N);
break;
case 2:printf("輸入你所要查詢的人的姓名:");
scanf("%s",fullname);
searchpoint=search(head,fullname);
printf("你所查詢的人的姓名為:%s",*&searchpoint->name);
printf("\n按回車鍵回到主選單。");
getchar();getchar();
break;
case 3: printf("輸入你要在哪個人後面插入:");
scanf("%s",fullname);
searchpoint=search(head,fullname);
printf("你所查詢的人的姓名為:%s",*&searchpoint->name);
insert(searchpoint);
print(head);
printf("\n按回車鍵回到主選單。");
getchar();getchar();
break;
case 4:print(head);
printf("\n輸入你所要刪除的人的姓名:");
scanf("%s",fullname);
searchpoint=search(head,fullname);
forepoint=search2(head,fullname);
del(forepoint,searchpoint);
break;
case 5:print(head);
printf("\n按回車鍵回到主選單。");
getchar();getchar();
break;
case 6:quit();
break;
default:printf("你輸入了非法字元!按回車鍵回到主選單。");
clrscr();
menu();
getchar();
}
}
}