鏈表存儲結構:每個節點包含兩個數據域,一個用來存放數據,另一個數據域用來保存下一個節點的地址(指針 )。這樣就將一些物理上不連續的內存組成鏈式存儲結構。也稱單鏈表。
代碼實現:
初始化鏈表
void ListInit(LinkList*list)
{
assert(list != NULL);
*list = (ListNode*)malloc(sizeof(ListNode));
if (*list == NULL)
{
exit(-1);
}
(*list)->next = NULL;//*list爲頭結點
}
銷燬鏈表
void ListDestory(LinkList*list)//不斷刪除頭結點之後的節點,最後將頭結點刪除
{
assert(list != NULL);
ListNode* tmp = (*list)->next;//tmp指向即將被刪除的節點,list之後的節點
while (tmp)
{
(*list)->next = (*list)->next->next;
free(tmp);
tmp = (*list)->next;
}
free(*list);//釋放頭結點
(*list) = NULL;
}
插入元素e
在第i個位置插入新節點,節點數據爲e,以頭節點之後爲第一個元素
Status InsertList(LinkList*list, int i, ListDataType e)
{
assert(list != NULL);
if (i < 1)
{
return ERROR;//位置從1開始
}
int j = 0;
ListNode*new = (ListNode*)malloc(sizeof(ListNode));
ListNode*cur = (*list);//將頭結點之後的節點作爲第一個節點
for (cur; cur&&j < i-1; cur = cur -> next,j++)
{
}
if (j == i - 1)//當j=i-1時,cur的後繼節點即就是要插入的節點new
{
new->data = e;
new->next = cur->next;
cur->next = new;
return OK;//插入成功
}
else
{
return ERROR;//插入失敗,i位置超過了鏈表的長度
}
}
刪除節點
刪除節點並用e返回刪除元素的數據,刪除失敗返回ERROR(0)
Status DeleteList(LinkList*list, int i, ListDataType *e)
{
assert(list != NULL);
int j = 0;
ListNode* cur = (*list);
ListNode*tmp=NULL;
while (i>1&&cur!=NULL)
{
cur = cur->next;
i--;
}
if (cur->next == NULL)
{
return ERROR;//未知錯誤,第i個位置不存在節點
}
else
{
tmp = cur->next;
cur->next = cur->next->next;//刪除節點cur->next
*e = tmp->data;
free(tmp);//釋放節點
return OK;
}
}
清空鏈表
將鏈表置空,釋放除頭節點之外的所有節點
void ListClear(LinkList*list)
{
assert(list != NULL);
ListNode*cur = (*list)->next;
while (cur)
{
(*list)->next = (*list)->next->next;
free(cur);
cur = (*list)->next;
}
}
判斷鏈表是否爲空
其實就是判斷頭結點之後是否還有節點
Status ListIsEmpty(LinkList list)
{
assert(list != NULL);
return list->next == NULL ? TRUE : FALSE;
}
獲取鏈表的節點個數
統計鏈表中的節點個數(除頭結點之外)
int GetListLength(LinkList list)
{
int count = 0;
ListNode*cur = list->next;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
獲取鏈表中第i個元素
找到鏈表中第i個節點,並將e記錄其數據,返回額,否則返回NULL表示未找到
ListDataType *GetListElem(LinkList list, int i, ListDataType *e)
{
assert(list != NULL);
ListNode* cur = list->next;
while (cur && i > 1)
{
cur = cur->next;
i--;
}
if (cur == NULL)
{
return NULL;//cur位置沒有數據,i值超過鏈表長度
}
else
{
*e = cur->data;
return e;
}
}
判斷鏈表中節點是否包含該數據
遍歷鏈表,判斷每個節點的數據是否等於e,若等於,返回TRUE,否則,返回FALSE,表示不包含
Status Locate_exist_Elem(LinkList list, ListDataType e)
{
ListNode*cur = list->next;
while (cur)
{
if (cur->data == e)
{
return TRUE;
}
cur = cur->next;
}
return FALSE;
}
單鏈表相對於順序表來講,插入和刪除操作比較方便,其時間複雜度爲O(1)。只需要改變next指針的指向就ok,不需要移動大量數據。
完整代碼及測試用例:
函數聲明和節點定義List.h文件:
#pragma once
#ifndef _LIST_H_
#define _LIST_H_
/*
帶頭指針的頭結點:統一第一個節點和後續節點的操作
動態實現單鏈表
*/
#define MAXSIZE 20//存儲空間
#define OK 1//函數狀態返回值,成功返回1,不成功返回0
#define ERROR 0//
#define TRUE 1//真假值,真爲1,假爲0
#define FALSE 0
typedef int Status;//Status是函數類型,其值是函數結果狀態代碼
typedef int ListDataType;
//定義鏈表節點類型
typedef struct Node
{
ListDataType data;
struct Node *next;
}ListNode, *LinkList;
//typedef struct ListNode;
void ListInit(LinkList*list);//初始化鏈表
void ListDestory(LinkList*list);//銷燬鏈表
Status InsertList(LinkList*list, int i, ListDataType e);//在第i個位置上插入元素
Status DeleteList(LinkList*list, int i, ListDataType *e);//刪除第i位的元素,並將數據用e返回
void ListClear(LinkList*list);//清空鏈表
Status ListIsEmpty(LinkList list);//判斷線性表是否爲空
int GetListLength(LinkList list);//獲取線性表長度
ListDataType *GetListElem(LinkList list, int i, ListDataType *e);//取第i個元素給e返回
Status Locate_exist_Elem(LinkList list, ListDataType e);//list鏈表中是否存在e元素
void PrintList(LinkList list);//打印鏈表函數
#endif
List.c包含函數實現
#include"List.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void ListInit(LinkList*list)
{
assert(list != NULL);
*list = (ListNode*)malloc(sizeof(ListNode));
if (*list == NULL)
{
exit(-1);
}
(*list)->next = NULL;//*list爲頭結點
}
void ListDestory(LinkList*list)//不斷刪除頭結點之後的節點,最後將頭結點刪除
{
assert(list != NULL);
ListNode* tmp = (*list)->next;//tmp指向即將被刪除的節點,list之後的節點
while (tmp)
{
(*list)->next = (*list)->next->next;
free(tmp);
tmp = (*list)->next;
}
free(*list);//釋放頭結點
(*list) = NULL;
}
Status InsertList(LinkList*list, int i, ListDataType e)
{
assert(list != NULL);
if (i < 1)
{
return ERROR;//位置從1開始
}
int j = 0;
ListNode*new = (ListNode*)malloc(sizeof(ListNode));
ListNode*cur = (*list);//將頭結點之後的節點作爲第一個節點
for (cur; cur&&j < i-1; cur = cur -> next,j++)
{
}
if (j == i - 1)//當j=i-1時,cur的後繼節點即就是要插入的節點new
{
new->data = e;
new->next = cur->next;
cur->next = new;
return OK;//插入成功
}
else
{
return ERROR;//插入失敗,i位置超過了鏈表的長度
}
}
Status DeleteList(LinkList*list, int i, ListDataType *e)
{
assert(list != NULL);
int j = 0;
ListNode* cur = (*list);
ListNode*tmp=NULL;
while (i>1&&cur!=NULL)
{
cur = cur->next;
i--;
}
if (cur->next == NULL)
{
return ERROR;//未知錯誤,第i個位置不存在節點
}
else
{
tmp = cur->next;
cur->next = cur->next->next;//刪除節點cur->next
*e = tmp->data;
free(tmp);//釋放節點
return OK;
}
}
void ListClear(LinkList*list)
{
assert(list != NULL);
ListNode*cur = (*list)->next;
while (cur)
{
(*list)->next = (*list)->next->next;
free(cur);
cur = (*list)->next;
}
}
Status ListIsEmpty(LinkList list)
{
assert(list != NULL);
return list->next == NULL ? TRUE : FALSE;
}
int GetListLength(LinkList list)
{
int count = 0;
ListNode*cur = list->next;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
ListDataType *GetListElem(LinkList list, int i, ListDataType *e)
{
assert(list != NULL);
ListNode* cur = list->next;
while (cur && i > 1)
{
cur = cur->next;
i--;
}
if (cur == NULL)
{
return NULL;//cur位置沒有數據,i值超過鏈表長度
}
else
{
*e = cur->data;
return e;
}
}
Status Locate_exist_Elem(LinkList list, ListDataType e)
{
ListNode*cur = list->next;
while (cur)
{
if (cur->data == e)
{
return TRUE;
}
cur = cur->next;
}
return FALSE;
}
void PrintList(LinkList list)
{
assert(list != NULL);
ListNode*cur = list->next;
printf("Head->");
for (; cur; cur = cur->next)
{
printf("%d->", cur->data);
}
printf("NULL\n");
}
test.c測試代碼:
#include<stdbool.h>
#include<stdlib.h>
#include"List.h"
void TestLink()
{
LinkList list;
ListDataType e;
int length;
bool empty;
ListInit(&list);
length = GetListLength(list);
printf("鏈表長度爲:%d\n", length);
empty = ListIsEmpty(&list);
printf("鏈表爲空?%d\n", empty);
InsertList(&list, 1, 1);
InsertList(&list, 1, 2);
InsertList(&list, 1, 3);
InsertList(&list, 1, 4);
InsertList(&list, 4, 5);
InsertList(&list, 6, 6);
InsertList(&list, 7, 7);
PrintList(list);
empty = Locate_exist_Elem(list, 9);
printf("鏈表中存在9?%d\n", empty);
empty = Locate_exist_Elem(list, 5);
printf("鏈表中存在5?%d\n", empty);
empty = ListIsEmpty(&list);
printf("鏈表爲空?%d\n", empty);
length = GetListLength(list);
printf("鏈表長度爲:%d\n", length);
PrintList(list);
DeleteList(&list, 1, &e);
length = GetListLength(list);
printf("鏈表長度爲:%d\n", length);
printf("刪除第1個的元素值爲%d\n", e);
empty = Locate_exist_Elem(list, e);
printf("鏈表中存在%d?%d\n", e,empty);
PrintList(list);
DeleteList(&list, 4, &e);
length = GetListLength(list);
printf("鏈表長度爲:%d\n", length);
printf("刪除第4個的元素值爲%d\n", e);
GetListElem(&list, 2, &e);
PrintList(list);
ListClear(&list);
length = GetListLength(list);
printf("鏈表長度爲:%d\n", length);
PrintList(list);
ListDestory(&list);
}
int main()
{
TestLink();
return 0;
}