本文對鏈表以及C/C++中的動態鏈表做詳細詮釋。
什么是鏈表?
鏈表是一種重要的數據結構,它最大的優點是可以進行動態的存儲分配。鏈表有單向鏈表,雙向鏈表,循環鏈表。對於c,這里我們只討論單向鏈表。
我們知道,內存是由棧和堆組成的。棧空間是由操作系統和編譯系統控制的,比如我們定義int a;這個a就是在棧中開辟內存單元的。而堆空間,則允許給用戶提供了虛擬空間, 在堆中是沒有變量名這個說法的,只能通過地址來找到內存中存放的東西。
既然是動態內存分配,當然有動態分配的特殊方法。在c中是以函數的形式實現的。
1.malloc函數
函數原型:void *malloc(unsigned int size)
函數的作用是:在內訓的動態存儲區開辟一個size個字節的連續空間,返回所分配區域的首字節地址。
可以看到,函數返回值是一個void指針,請注意,void指針不是一個可以指向任何類型數據的指針,而是 說,不指向任何類型的數據,僅僅是提供了一個地址。
因而,你想讓這個指針指向int型數據,要進行顯式的類型轉換(強制類型轉換),即在前面加(int *)。一般來說,如果不加,是可以自動進行隱式類型轉換的。
2.calloc函數
函數原型:void *calloc(unsigned n,unsigned size)
作用:開辟n個長度為size的連續空間。一般用來保存一個數組。
3.realloc函數
原型:void *realloc(void *p,unsigned int size)
作用:用來重新分配已經分配的動態空間的大小。
4.free函數
原型:void free(void *p)
作用:把已經分配的動態空間釋放掉。
======================================================================
言歸鏈表:
一個鏈表,是由許多節點組成的。可以自由的刪除、添加。指向首節點的指針叫做head指針,它是鏈表的唯一標示。每個節點包含兩部分,一是數據,而是下一個節點的地址。通過這個下個節點的地址,建立了整個鏈表的聯系。
如何建立一個鏈表呢?
用結構體建立鏈表當然是再合適不過了。
比如:現在建立一個靜態鏈表。
struct S
{
int a;
struct S *next;
}S1,S2,S3;
struct S *head;
S1.a=1;S2.a=2;S3.a=3;
head=&S1;
S1.next=&S2;
S2.next=&S3;
S3.next=NULL; //請注意讓最有一個節點存放的地址為NULL。
這樣,我們就建立了一個有三個節點的靜態鏈表。
如何建立一個動態鏈表呢?又如何添加、刪除節點,更進一步說,怎么使得鏈表有序,並且進行刪除添加操作后使之依然有序 ?
建立動態鏈表,就是可以隨時根據需要來增加結點 。看代碼:
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct S)
struct S
{
int a;
struct S *next;
};
int n; //全局變量n,記錄節點個數。未賦初值默認為0;
struct S *creat_autolist(void) //函數,來創建一個動態鏈表
{
struct S *head; //頭指針;
struct S *p0,*p1; //p0為當前節點;
p0=p1=(struct S*)malloc(LEN);//用malloc函數開辟一個結點的空間 ;
scanf("%d",&p0->a);//輸入數據;
head=NULL;
while(p0->a!=0) //循環,輸入的a不為0則繼續輸入;
{
n++;
if(n==1) head=p0; //是否為第一個結點;
else p1=p0->next;
p1=p0; //讓p1也指向p0所指向的結點
p0= (struct S*)malloc(LEN); //在開辟一個節點;
scanf("%d",&p0->a);
}
p1->next=NULL;//尾結點的指針部分為NULL
return (head);
}
void main()
{
struct S *head,*pt;
head=creat();
pt=head;
/*
這是輸出鏈表的方法
*/
if(head!=NULL)
{
do
{
printf("%d\n",pt->a);
pt=pt->next;
}while(pt!=NULL);
}
}
至此,動態鏈表的創建和輸出已經實現。
怎么刪除結點呢?實際上就是改變要刪除的結點的前后的兩個節點中地址的指向。
怎么添加結點呢?實際上也是改變指向。
使其做到有序?
那么,我們就要進行一個大小比較的過程了。不過,要考慮在表首,表中,表尾三種情況。
下面給出一個小栗子:
要進行鏈表的結點添加,並順序。
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define LEN sizeof(struct Student)
struct Student
{
long num;
double score;
struct Student *next;
};
int n=0;
void print(struct Student *head)
{
struct Student *pt;
pt=head;
printf("there are %d records:\n");
if(head!=NULL)
{
do
{
printf("%ld,%5.1lf",pt->num,pt->score);
pt=pt->next;
}while(pt!=NULL);
}
}
struct Student *creat()
{
struct Student *head,*p0,*p1;
head=NULL;
printf("*****creat list*****");
printf("please input record(0,0 for exit)\n");
p0=(struct Student *)malloc(LEN);
scanf("%ld,%lf",&p0->num,&p0->score);
while(p0->num!=0)
{
head=insert(head,p0);
p0=(struct Student *)malloc(LEN);
scanf("%ld,%lf",&p0->num,&p0->score);
}
return (head);
}
struct Student *insert(struct Student *head,struct Student *stu)
{
struct Student *p0,*p1,*p2;
p0=stu;
if(head==NULL)
{
head=p0;
p0->next=NULL;
}
else
{
p1=head;
while(p0->num>p1->num&&p1->next!=NULL) //這是個遍歷
{
p2=p1;
p1=p1->next;
}
if(p0->num<=p1->num)
{
if(head==p1)
{
head=p0;
p0->next=p1;
}
else
{
p2.next=p0;
p0.next=p1;
}
}
else
{
p1.next=p0;
p0.next=NULL;
}
}
n++;
return(head);
}
