資料結構——單鏈表實現
阿新 • • 發佈:2019-01-01
鏈式儲存特點
在鏈式儲存中,節點之間的儲存單元地址可能是不連續的。鏈式儲存中每個結點都包含兩部分:儲存元素本身的資料域和儲存結點地址的指標域。結點中的指標指向的是下一個結點,也就是儲存的下一個結點的地址。
鏈式儲存的實現
1.建立連結串列
在建立連結串列時,頭結點不儲存資料,但可以儲存連結串列的資訊。
struct Header
{
int length;//記錄連結串列大小
struct Node *next; //指向第一個結點的指標
};
儲存資料的結點包含兩部分內容:資料域和指標域。
struct Node
{
int data; //資料域
struct Node *next; //指向下一個結點的指標
};
為了方便定義,將兩個struct 用typedef重新定義:
typedef struct Node List; //節點
typedef struct Header pHead; //頭節點
建立連結串列時,只需要建立一個頭結點,每儲存一個元素就分配一個儲存單元,然後將儲存單元的地址儲存在上一個結點:
pHead* creatList()
{
pHead* ph=(pHead *)malloc(sizeof(pHead)); //為頭結點分配記憶體
ph->length=0; //為頭結點初始化,此時連結串列長度為0
ph->next=NULL;
return ph; //將頭結點地址返回
}
2.獲取連結串列大小
//獲取連結串列的大小
int Size(pHead* ph)
{
if(ph==NULL)
{
printf("傳入引數有誤!");
}
return ph->length;
}
3.插入元素
在連結串列中插入元素時要比在順序表中快。比如在pos位置插入,則先斷開pos-1與pos的連結,然後將pos-1結點的指標指向val結點,將val結點的指標指向pos。
//插入元素,在pos位置插入元素val
void Insert(pHead* ph,int pos,int val)
{
if(ph==NULL || pos<0 || pos>ph->length)
{
printf("傳入引數有誤!");
return;
}
//首先將值val儲存在一個結點中
List *pval=(List *)malloc(sizeof(List));
pval->data=val;
List *pCur=ph->next;
if(pos==0) //插在首節點
{
ph->next=pval;
pval->next=pCur;
}
else
{
for(int i=1;i<pos;i++)
{
pCur=pCur->next;
}
pval->next=pCur->next;
pCur->next=pval;
}
ph->length++; //長度加1
return;
}
4.查詢某個元素
查詢連結串列中的某個元素,其效率沒有順序表高,因為不管查詢的元素在哪個位置,都需要將它前面的元素都全部遍歷才能找到它。
//查詢某個元素,並返回它的結點
List* find(pHead* ph,int val)
{
if(ph==NULL)
{
printf("輸入引數有誤");
return NULL;
}
//遍歷連結串列來查詢元素
List* pTmp=ph->next;
do
{
if(pTmp->data==val)
{
return pTmp;
}
pTmp=pTmp->next;
}while(pTmp->next!=NULL);
printf("沒有值為%d的元素\n",val);
return NULL;
}
5.刪除元素
在刪除元素時,首先將被刪除元素與上下結點之間的連結斷開,然後將這兩個上下結點重新連結。
//刪除節點,刪除值為val的元素,刪除成功,返回刪除的元素
void Delete(pHead * ph,int val)
{
if(ph==NULL)
{
printf("傳入引數有誤");
return;
}
List* pval=find(ph,val);
if(pval==NULL)
{
printf("沒有找到值為%d的元素\n",val);
free(pval); //釋放結點
return;
}
List* pRe=ph->next;
List* pCur=NULL;
if(pRe->data==val) //如果刪除的是第一個節點
{
ph->next=pRe->next;
ph->length--;
free(pRe); //釋放結點
return;
}
else
{
for(int i=0;i<ph->length;i++)
{
pCur=pRe->next;
if(pCur->data==val)
{
pRe->next=pCur->next;
ph->length--;
return;
}
pRe=pRe->next;
}
free(pCur); //釋放結點
}
return;
}
6.銷燬連結串列
銷燬連結串列時,將連結串列中每個元素結點釋放,頭結點可以釋放,也可以保留,將其置為初始化狀態。
//銷燬連結串列
void Destroy(pHead *ph)
{
List* pCur=ph->next;
List* pTmp;
if(pCur==NULL)
{
printf("傳入引數有誤");
}
while(pCur->next!=NULL)
{
pTmp=pCur->next;
free(pCur); //將結點釋放
pCur=pTmp;
}
ph->length=0; //初始化頭結點
ph->next=NULL;
printf("連結串列已銷燬!\n");
}
7.遍歷列印連結串列
//遍歷列印連結串列
void print(pHead * ph)
{
List * pTmp=ph->next;
if(ph==NULL)
{
printf("傳入引數有誤");
}
while(pTmp!=NULL)
{
printf("%d ",pTmp->data);
pTmp=pTmp->next;
}
printf("\n");
}
8.樣例測試
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//所有函式宣告
pHead* creatList(); //建立連結串列
int Size(pHead* ); //獲取連結串列的大小
void Insert(pHead*,int,int); //插入元素
List* find(pHead*,int); //查詢某個元素
void Delete(pHead*,int); //刪除節點
void Destroy(pHead*); //銷燬連結串列
void print(pHead*); //遍歷列印連結串列
int main()
{
List * ret;
pHead * ph=creatList();
int arr[10]={1,2,3,4,5,6,7,8,9,0};
for(int i=0;i<10;i++)
{
Insert(ph,0,arr[i]);
}
printf("連結串列長度:%d\n",Size(ph));
print(ph);
printf("刪除連結串列中的節點\n");
int num;
scanf("%d",&num);
Delete(ph,num);
printf("元素刪除成功,刪除元素%d後,連結串列中元素為:\n",num);
print(ph);
ret=find(ph,3);
if(ret)
{
printf("get!\n");
}
else
{
printf("No!\n");
}
Destroy(ph);
return 0;
}
結果:
連結串列長度:10
0 9 8 7 6 5 4 3 2 1
刪除連結串列中的節點
2
元素刪除成功,刪除元素2後,連結串列中元素為:
0 9 8 7 6 5 4 3 1
get!
連結串列已銷燬!