鏈表
鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱爲結點)組成,結點可以在運行時動態生成。每個結點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。
鏈表分別有一下的操作
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 動態申請一個節點
SListNode* BuySListNode(SLTDateType x);
// 單鏈表打印
void SListPrint(SListNode* plist);
// 單鏈表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 單鏈表的頭插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 單鏈表的尾刪
void SListPopBack(SListNode** pplist);
// 單鏈表頭刪
void SListPopFront(SListNode** pplist);
// 單鏈表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 單鏈表在pos位置之後插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 單鏈表刪除pos位置之後的值
void SListEraseAfter(SListNode* pos);
// 單鏈表的銷燬
void SListDestory(SList* plist);
定義鏈表結構
這是帶頭指針而不帶頭節點的單鏈表定義方式,我們需要一個額外的結構體來定義。代碼如下
typedef struct node{
int num;
node* next;
}node;
typedef struct{
struct node* head;
}singlelist;
鏈表的初始化
創建一個空鏈表,並且初始化它
void singleListInit(SingleList* sl)
{
//空鏈表
sl->_head = NULL;
}
Node* creatNode(Type data)
{
Node* node = (Node*)malloc(sizeof(Node));
node->_data = data;
node->_next = NULL;
return node;
}
鏈表的頭插
即每次都在頭指針的位置插入一個結點,需要改變指針指向,代碼如下
void singleListPushFront(SingleList* sl, Type data)
{
Node* node = creatNode(data);
//是否爲空表
if (sl->_head == NULL)
{
sl->_head = node;
}
else
{
node->_next = sl->_head;
sl->_head = node;
}
}
鏈表的頭刪
既然是刪除,那麼切記不可忘記釋放空間,否則就會造成內存泄露,別切釋放的時候需要記錄當前要刪除的下一個結點,否則就會出現結點丟失
void singleListPopFront(SingleList* sl)
{
if (sl->_head)
{
Node* cur = sl->_head;
sl->_head = cur->_next;
free(cur);
}
}
錯誤的代碼形式之一如下
void singleListPop1(Node* head)
{
if (head)
{
Node* newH = head->_next;
free(head);
head = newH;
}
}
上述錯誤行成主要是爲傳入二級指針,正確寫法如下
void singleListPop(Node** head)
{
if (*head)
{
Node* newH = (*head)->_next;
free(*head);
*head = newH;
}
}
鏈表的尾插
尾插,顧名思義,每次在鏈表的末端進行插入節點的操作
void singleListPushBack(SingleList* sl, Type data)
{
Node* node = creatNode(data);
if (sl->_head == NULL)
sl->_head = node;
else
{
//找到最後一個數據
// last newNode
Node* last = sl->_head;
while (last->_next)
last = last->_next;
//尾插
last->_next = node;
}
}
鏈表的尾刪
尾刪,即刪除尾部的結點,話不多說,代碼如下
void singleListPopBack(SingleList* sl)
{
//找到最後一個節點,並且,修改被刪除節點的前驅節點的執行
if (sl->_head)
{
//找到最後一個節點,遍歷的過程中,更新prev
Node* prev = NULL;
Node* tail = sl->_head;
while (tail->_next)
{
prev = tail;
tail = tail->_next;
}
//如果刪除的爲頭結點, 或者鏈表中只要一個節點
//和下面判斷等價if (prev == NULL)
if (tail == sl->_head)
sl->_head = NULL;
else
prev->_next = NULL;
free(tail);
}
}
鏈表的結點插入
ps:這裏傳入的是找到所要插入結點的位置
void singleListInsertAfter(Node* pos, Type data)
{
if (pos == NULL)
return;
// pos newNode next
Node* newNode = creatNode(data);
//注意先後順序
newNode->_next = pos->_next;
pos->_next = newNode;
}
鏈表節點的刪除
傳入的參數也是找到的所要刪除的結點
void singleListEraseAfter(Node* pos)
{
Node* next;
if (pos == NULL)
return;
//pos next
next = pos->_next;
//確保next非空指針, pos->_next->_next
if (next)
{
pos->_next = next->_next;
free(next);
}
}
鏈表的刪除
刪除鏈表,要遍歷整個鏈表直至NULL每次刪除一個結點,直至刪除完
void singleListDestroy(SingleList* sl)
{
Node* cur = sl->_head;
while (cur)
{
Node* next = cur->_next;
free(cur);
cur = next;
}
}
鏈表的打印
打印想必都能知道,也是遍歷這個鏈表,每次打印數據域的數據,知道遍歷到NULL
void singleListPrint(SingleList* sl)
{
Node* cur = sl->_head;
while (cur)
{
printf("%d ", cur->_data);
cur = cur->_next;
}
printf("\n");
}
鏈表的基本操作就上述這些,此外還有一種常用的雙向循環鏈表的結構,在這裏就不多說雙向循環鏈表的結構我也寫了,代碼如下,供大家參考
雙向循環鏈表
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node* next;//指向後繼
struct node* prev;//指向先驅
}noed;
typedef struct List
{
node* head;
}list;
//生成結點
node* creatNode(int data)
{
node* Node = (node*)malloc(sizeof(node));
Node->prev = Node->next = NULL;
Node->data = data;
return Node;
}
//初始化鏈表
void litinit(list *ls)
{
ls->head = creatNode(0);
ls->head->next = ls->head;
ls->head->prev = ls->head;
}
//尾插
void listPushBack(list* ls, int data)
{
node* Node = creatNode(data);
node* p = ls->head->prev;
Node->next = p->next;
p->next = Node;
ls->head->prev = Node;
Node->prev = p;
}
//頭插
void listPopFront(list* ls)
{
if(ls->head->next == ls->head)
return ;
node* f = ls->head->next;
node* n = f->next;
ls->head->next = n;
n->prev = ls->head;
free(f);
}
//隨機插入
void listInsert(node* pos, int data)
{
node* p = pos->prev;
node* Node = creatNode(data);
Node->next = pos;
Node->prev = p;
p->next = Node;
pos->prev = Node;
}
//尾刪
void listPopBack(list* ls)
{
node* last,*p;
last = ls->head->prev;
p = last->prev;
p->next = ls->head;
ls->head->prev = p;
free(last);
}
//頭插
void listPushFront(list* ls, int data)
{
node* f = ls->head->next;
node* Node = creatNode(data);
Node->next = f;
f->prev = Node;
Node->prev = ls->head;
ls->head->next = Node;
}
//鏈表刪除pos結點
void listErase(node* pos)
{
if(pos->next = pos)
return ;
node* f = pos->prev;
node* n = pos->next;
f->next = n;
n->prev = f;
free(pos);
}//鏈表打印
void printList(list* ls)
{
node* n = ls->head->next;
while(n!=ls->head)
{
printf("%d ",n->data);
n = n->next;
}
printf("\n");
}
//鏈表銷燬
void listDesroy(list* ls)
{
node* c = ls->head->next;
while(c!=ls->head)
{
node* p =c->next;;
free(c);
c = p;
}
free(ls->head);
ls->head = NULL;
}
int main(int argc, char const *argv[])
{
list ls;
return 0;
}