1. 程式人生 > >常見演算法:C語言中連結串列的操作(建立,插入,刪除,輸出)

常見演算法:C語言中連結串列的操作(建立,插入,刪除,輸出)

連結串列中最簡單的一種是單向連結串列,它包含兩個域,一個資訊域和一個指標域。這個連結指向列表中的下一個節點,而最後一個節點則指向一個空值。

Singly-linked-list.svg
一個單向連結串列包含兩個值: 當前節點的值和一個指向下一個節點的連結

一個單向連結串列的節點被分成兩個部分。第一個部分儲存或者顯示關於節點的資訊,第二個部分儲存下一個節點的地址。單向連結串列只可向一個方向遍歷。

連結串列最基本的結構是在每個節點儲存資料和到下一個節點的地址,在最後一個節點儲存一個特殊的結束標記,另外在一個固定的位置儲存指向第一個節點的指標,有的時候也會同時儲存指向最後一個節點的指標。一般查詢一個節點的時候需要從第一個節點開始每次訪問下一個節點,一直訪問到需要的位置。但是也可以提前把一個節點的位置另外儲存起來,然後直接訪問。當然如果只是訪問資料就沒必要了,不如在連結串列上儲存指向實際資料的指標。這樣一般是為了訪問連結串列中的下一個或者前一個(需要儲存反向的指標,見下面的雙向連結串列)節點。

相對於下面的雙向連結串列,這種普通的,每個節點只有一個指標的連結串列也叫單向連結串列,或者單鏈表,通常用在每次都只會按順序遍歷這個連結串列的時候(例如圖的鄰接表,通常都是按固定順序訪問的)。

例1,建立連結串列儲存學生的資訊,並且可以進行,插入,刪除操作,並將學生的資訊輸出

#include <stdio.h>
#include<malloc.h>
#define LEN sizeof(struct student )
#define NULL 0
struct student 
{
	int num;
	float score;
	struct student *next;
};
int n;
//建立連結串列
struct student *create(void)
{
	struct student *head, *p1,*p2;
	n=0;
	p1=p2=(struct student *)malloc(LEN);
	scanf("%d %f",&p1->next,&p1->score);
	head=NULL;
	while(p1->num!=0)
	{
		n=n+1;
		if(n==1) head=p1;    //p1是指向新開闢的結點
		else p2->next=p1;
		p2=p1;    //p2指向連結串列中的最後一個基點
		p1=(struct student *)malloc(LEN); //開闢新的結點,並且使p1指向他
		scanf("%d %f",&p1->num,&p1->score);
	}
	p2->next=NULL;
	return (head);
}
//刪除結點
struct student *del(struct student  *head,long num)
{
	struct student *p1,*p2;
	
	if(head==NULL)   {printf("\nlist null!\n");goto end;}
	p1=head;
	while(num!=p1->num && p1->next!=NULL)   //p1指向不是所要找的結點,並且後面還有結點
	{
		p2=p1;
		p1=p1->next;      //p1後移一個及誒單
	}       //p1後移一個結點
	if(num==p1->num)     //找到了
	{
		if(p1==head)  head=p1->next;    //若p1指向的是首結點,把第二個結點的地址head

		else p2->next=p1->next;      //or 將下一個結點的地址賦給前一個結點地址
		printf("delete:%d\n",num);
		n=n-1;
		free(p1);
	}
	else  printf("%dnot been found !\n",num);
	end:
	return(head);


}
//插入學生資訊
 struct student *insert(struct student *head ,struct student *stud)
{
	struct student *p0,*p1,*p2;
	p1=head;         //使p1指向第一個結點
	p0=stud;        //p0指向要插入的結點
	if(head==NULL)     //原來的連結串列是空表
	{
		head=p0,p0->next=NULL; //使p0指向的結點作為頭結點
	}
	else
	{
		while ((p1->num>p1->num)&&(p1->next!=NULL))
		{
			p2=p1;     //使p2指向剛才p1指向的及誒按
			p1=p1->next;    //p1後移一個結點
		}
		if(p0->num<=p1->num)
		{
			if(head==p1)  head=p0;   //插到原來第一個結點之前
			else p2->next=p0;        //插到p2指向的結點之後
			p0->next=p1;
		}
		else
		{
			p1->next=p0;p0->next=NULL;    //插到最後的結點之後
		}
	}
	n=n+1;                            //結點數加1
	return (head);
}
//輸出連結串列
 void print(struct student *head)
{
	struct student *p;
	p=head;
	if(head!=NULL)
		do
	{
		printf("%d %f\n",p->num,p->score);
		p=p->next;

	}
	while(p!=NULL);
}
//main函式
 void main()
{
	struct student *head,stu;
	long del_num;
	printf("Input records:\n");
	head=create();        //建立連結串列,返回頭指標
	print(head);          //輸出全部結點

	printf("\nInput the deleted number:\n");
	scanf("%ld",&del_num);       //輸入要刪除的學號
	while(del_num!=0)
	{
	head=del(head,del_num);      //刪除後連結串列的頭指標
	print(head);                       //輸出全部結點
	printf("Input the deleted number:\n");
	scanf("%ld",&del_num); 
	}

	printf("\nInput the inserted record:\n");
	stu=(struct student *)malloc(LEN);
	scanf("%d %f",&stu->num,&stu->score);     //輸入要插入的結點
	{
	head=insert(head,&stu);                 //插入一個結點,返回頭指標的
	print(head);                                     //輸出全部結點
	printf("\nInput the inserted record:\n");
	stu=(struct student *)malloc(LEN);
	scanf("%d %f",&stu->num,&stu->score);
	}
}