1、鏈表的概念:鏈表是一種非連續、非順序的數據結構。
2、鏈表的分類:主要分爲這三類:單鏈表、雙向鏈表、循環鏈表,這三者又可以通過組合形成總共8種鏈表。
3、鏈表的基本操作:
// 動態鏈表的基本操作:
//不帶頭節點的單鏈表
typedef int SDataType;
// 節點結構
typedef struct SListNode
{
SDataType _data;
struct SListNode* _pNext;
}Node;
// 給一個鏈表結構
typedef struct SList
{
Node* _pHead;
}SList;
// 鏈表的初始化
void SListInit(SList* pl){
assert(pl);
pl->_pHead = NULL;
}
// 在鏈表中尾插值爲data的節點
void SListPushBack(SList* pl, SDataType data){
assert(pl);
Node* node = (Node*)malloc(sizeof(Node));
node->_data = data;
// 如果鏈表中只有一個結點
if (pl->_pHead == NULL){
node->_pNext = NULL;
pl->_pHead = node;
return;
}
// 不止一個結點,先找到最後一個結點
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
cur = cur->_pNext;
}
cur->_pNext = node;
}
// 刪除鏈表最後一個節點
void SListPopBack(SList* pl){
assert(pl);
// 只有一個結點
if (pl->_pHead->_pNext == NULL){
free(pl->_pHead);
pl->_pHead == NULL;
}
// 不止一個結點
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
cur = cur->_pNext;
}
free(cur->_pNext);
cur->_pNext = NULL;
}
// 在鏈表第一個元素前插入值爲data的節點 (頭插)
void SListPushFront(SList* pl, SDataType data){
assert(pl);
Node* node = (Node*)malloc(sizeof(Node));
node->_data = data;
node->_pNext = pl->_pHead;
pl->_pHead = node;
}
// 刪除鏈表中第一個節點
void SListPopFront(SList* pl){
assert(pl);
Node* next = pl->_pHead->_pNext;
free(pl->_pHead);
pl->_pHead == next;
}
// 在鏈表pos位置後插入置爲data的節點
void SListInsertAfter(Node* pos, SDataType data){
Node* node = (Node*)malloc(sizeof(Node));
node->_data = data;
node->_pNext = pos->_pNext;
pos->_pNext = node;
}
// 刪除pos後的結點
void SListEraseAfter(SListNode* pos){
Node* cur = pos->_pNext;
pos->_pNext = pos->_pNext->_pNext;
free(pos->_pNext);
free(cur);
}
// 刪除鏈表中值爲data的節點
void SListErase(SList* pl, SDataType data){
// 鏈表爲空
if (pl == NULL){
return;
}
// 是鏈表的第一個結點
if (pl->_pHead->_data == data){
Node* next = pl->_pHead->_pNext;
free(pl->_pHead);
pl->_pHead = next;
return;
}
// 遍歷
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
if (cur->_pNext->_data == data){
Node* next = cur->_pNext->_pNext;
free(cur->_pNext);
cur->_pNext = next;
}
cur = cur->_pNext;
}
}
// 在鏈表中查找值爲data的節點,找到返回該節點的地址,否則返回空
Node* SListFind(SList* pl, SDataType data){
if (pl == NULL){
return NULL;
}
if (pl->_pHead->_data == data){
return pl->_pHead;
}
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
if (cur->_pNext->_data == data){
return cur->_pNext;
cur = cur->_pNext;
}
}
return NULL;
}
// 銷燬鏈表
void SListDestroy(SList* pl){
// 刪除所有結點
Node* cur = pl->_pHead;
Node* next = cur->_pNext;
while (cur->_pNext != NULL){
next = cur->_pNext;
free(cur);
}
pl->_pHead = NULL;
}
// 獲取鏈表中有效節點的個數
int SListSize(SList* pl){
int count = 0;
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
cur = cur->_pNext;
count++;
}
return count;
}
// 檢測鏈表是否爲空
int SListEmpty(SList* pl){
if (pl->_pHead == NULL){
return 1;
}
else
return 0;
}
// 獲取鏈表的第一個節點
Node* SListFront(SList* pl){
assert(pl);
return pl->_pHead;
}
// 獲取鏈表的第二個節點
Node* SListBack(SList* pl){
assert(pl);
return pl->_pHead->_pNext;
}
// 刪除鏈表中第一個值爲data的節點
void SListRemove(SList* pl, SDataType data){
assert(pl);
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
if (cur->_pNext->_data == data){
Node* next = cur->_pNext->_pNext;
free(cur->_pNext);
cur = next;
break;
}
}
}
// 刪除鏈表中所有值爲data的節點
void SListRemoveAll(SList* pl, SDataType data){
assert(pl);
Node* cur = pl->_pHead;
while (cur->_pNext != NULL){
if (cur->_pNext->_data == data){
Node* next = cur->_pNext->_pNext;
free(cur->_pNext);
cur = next;
}
}
}
// 熟悉雙向鏈表的結構,並實現帶頭結點的雙向循環鏈表的以下基本操作:
typedef int DLDataType;
typedef struct DListNode
{
struct DListNode* _pNext;
struct DListNode* _pPre;
DLDataType _data;
}DLNode;
// 初始化雙向鏈表
void DListInit(DLNode* pHead){
assert(pHead);
pHead->_pNext = NULL;
pHead->_pPre = NULL;
}
// 尾插
void DListPushBack(DLNode* pHead, DLDataType data){
assert(pHead);
DLNode* node = (DLNode*)malloc(sizeof(DLNode));
node->_data = data;
node->_pNext = pHead;
node->_pPre = pHead->_pPre;
pHead->_pPre->_pNext = node;
pHead->_pPre = node;
}
// 尾刪
void DListPopBack(DLNode* pHead){
assert(pHead);
if (pHead->_pNext = pHead){
return;
}
else{
pHead->_pPre = pHead->_pPre->_pPre;
free(pHead->_pPre->_pNext);
pHead->_pPre->_pNext = pHead;
}
}
// 頭插
void DListPushFront(DLNode* pHead, DLDataType data){
assert(pHead);
DLNode* node = (DLNode*)malloc(sizeof(DLNode));
node->_data = data;
node->_pNext = pHead->_pNext;
node->_pPre = pHead;
pHead->_pNext->_pPre = node;
pHead->_pNext = node;
}
// 頭刪
void DListPopFront(DLNode* pHead){
assert(pHead);
DLNode* cur = pHead->_pNext;
pHead->_pNext->_pNext->_pPre = pHead;
pHead->_pNext = pHead->_pNext->_pNext;
free(cur);
cur = NULL;
}
// 在鏈表中查找值爲data的節點,找到返回節點的位置
DLNode* DListFind(DLNode* pHead, DLDataType data){
assert(pHead);
DLNode* cur = pHead->_pNext;
while (cur != pHead){
if (cur->_data == data){
return cur;
}
cur = cur->_pNext;
}
return NULL;
}
// 在pos位置(插入成功後新節點實際在pos前)插入值爲data的元素
void DListInsert(DLNode* pos, DLDataType data){
assert(pos);
DLNode* node = (DLNode*)malloc(sizeof(DLNode));
node->_data = data;
node->_pNext = pos;
node->_pPre = pos->_pPre;
pos->_pPre->_pNext = node;
pos->_pPre = node;
}
// 刪除pos位置的節點
void DListErase(DLNode* pos){
assert(pos);
pos->_pNext->_pPre = pos->_pNext;
pos->_pPre->_pNext = pos->_pPre;
free(pos);
pos = NULL;
}
// 將鏈表中的所有節點清空
void DListClear(DLNode* pHead){
assert(pHead);
DLNode* cur = pHead->_pNext;
while (cur != pHead){
DLNode* next = cur->_pNext;
cur->_pNext->_pPre = cur->_pPre;
cur->_pPre->_pNext = cur->_pNext;
free(cur);
cur = next->_pNext;
}
}
// 銷燬鏈表
void DListDestroy(DLNode** pHead){
assert(pHead);
DLNode* cur = *pHead;
cur = cur->_pNext;
while (cur != *pHead)
{
DLNode* next = cur->_pNext;
free(next);
}
free(*pHead);
*pHead = NULL;
}