雙向迴圈帶頭連結串列的基礎操作(增刪改查)
阿新 • • 發佈:2018-12-14
1.定義連結串列結點的結構
typedef int CLDataType;
//結點型別
typedef struct ListNode
{
CLDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
//連結串列的頭
typedef struct List
{
ListNode* _head;
}List;
2.宣告各函式介面
//建立一個雙向迴圈連結串列結點
ListNode* BuyListNode(CLDataType x);
//初始化雙向迴圈帶頭連結串列
void ListInit(List* pcl);
//銷燬雙向迴圈帶頭連結串列
void ListDestory(List* pcl);
//尾插
void ListPushBack(List* pcl, CLDataType x);
//頭插
void ListPushFront(List* pcl, CLDataType x);
//指定位置插入結點
void ListInsert(ListNode* pos, CLDataType x);
//尾刪
void ListPopBack(List* pcl);
//頭刪
void ListPopFront(List* pcl);
//指定位置刪除(不能是頭結點)
void ListErase (List* pcl, ListNode* pos);
//遍歷列印連結串列
void ListPrint(List* pcl);
//連結串列的長度
int ListSize(List* pcl);
//判斷連結串列是否為空(為空返回0,非空返回1)
int ListEmpty(List* pcl);
//尋找指定資料的結點(找到返回地址,找不到返回NULL)
ListNode* FindListNode(List* pcl, CLDataType x);
3.各函式實現
//建立一個雙向迴圈連結串列結點
ListNode* BuyListNode(CLDataType x)
{
ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
if (cur == NULL)
{
perror("use malloc");
exit(1);
}
cur->_data = x;
cur->_next = NULL;
cur->_prev = NULL;
return cur;
}
//初始化雙向迴圈帶頭連結串列
void ListInit(List* pcl)
{
assert(pcl);
ListNode* head = BuyListNode(0);
pcl->_head = head;
pcl->_head->_next = pcl->_head;
pcl->_head->_prev = pcl->_head;
}
//銷燬雙向迴圈帶頭連結串列
void ListDestory(List* pcl)
{
assert(pcl);
ListNode* cur = pcl->_head->_next;
while (cur != pcl->_head)
{
ListNode* tmp = cur->_next;
free(cur);
cur = tmp;
}
free(pcl->_head);
pcl->_head = NULL;
}
//尾插
void ListPushBack(List* pcl, CLDataType x)
{
assert(pcl);
//尾插和在頭結點前面插入一個結點一樣
ListInsert(pcl->_head, x);
}
//頭插
void ListPushFront(List* pcl, CLDataType x)
{
assert(pcl);
//頭插和在第一個結點前面插入一樣
ListInsert(pcl->_head->_next, x);
}
//指定位置前面插入結點
void ListInsert(ListNode* pos, CLDataType x)
{
assert(pos);
ListNode* newnode = BuyListNode(x);
//儲存前面結點(建議這麼寫,如果直接用指標完會太繞了)
ListNode* prev = pos->_prev;
//prev-newnode-pos指標連線起來
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
//尾刪
void ListPopBack(List* pcl)
{
assert(pcl);
//尾刪和在刪除指定最後一個結點一樣
ListErase(pcl, pcl->_head->_prev);
}
//頭刪
void ListPopFront(List* pcl)
{
assert(pcl);
//頭刪和刪除指定第一個結點一樣
ListErase(pcl, pcl->_head->_next);
}
//指定位置刪除結點
void ListErase(List* pcl, ListNode* pos)
{
assert(pos);
//刪除的結點不能是頭結點
assert(pos != pcl->_head);
//儲存pos前面結點
ListNode* prev = pos->_prev;
//儲存pos後面結點
ListNode* next = pos->_next;
//prev pos next(pos為刪除結點)
prev->_next = next;
next->_prev = prev;
free(pos);
pos = NULL;
}
//遍歷列印連結串列
void ListPrint(List* pcl)
{
assert(pcl);
ListNode* cur = pcl->_head->_next;
//從頭結點的下一個結點開始遍歷
while (cur != pcl->_head)
{
printf("%d-->", cur->_data);
cur = cur->_next;
}
printf("over\n");
}
//連結串列的長度
int ListSize(List* pcl)
{
assert(pcl);
ListNode* cur = pcl->_head->_next;
int count = 0;
//遍歷一遍連結串列(不算頭結點)
while (cur != pcl->_head)
{
count++;
cur = cur->_next;
}
return count;
}
//判斷連結串列是否為空(為空返回0,非空返回1)
int ListEmpty(List* pcl)
{
assert(pcl);
//prev和next如果都指向自己,則連結串列為空
return ((pcl->_head->_next == pcl->_head) && (pcl->_head->_prev == pcl->_head)) ? 0 : 1;
}
//尋找指定資料的結點(找到返回地址,找不到返回NULL)
ListNode* FindListNode(List* pcl, CLDataType x)
{
assert(pcl);
ListNode* cur = pcl->_head->_next;
//遍歷連結串列找到相同資料返回地址,找不到則返NULL
while (cur != pcl->_head)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}