双向链表
1.双向链表的结构
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;//记录下一个结点的地址
struct ListNode* prev;//记录上一个结点的地址
}ListNode;
2.双向链表的基本操作
2.1创建返回链表的头结点
这里所说的头结点就是哨兵位头结点(不存放有效数据)。因为后面可能还要申请结点,所以多写一个函数来申请结点。
代码
//动态申请一个结点.
ListNode* BuyListNode(LTDataType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
perror("malloc");
return NULL;
}
newnode->data = x;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
// 创建返回链表的头结点.
ListNode* ListCreate()
{
ListNode* head = BuyListNode(-1);//随便传个有效数据即可
head->next = head;
head->prev = head;
return head;
}
2.2双向链表尾插
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
ListNode* tail = pHead->prev;
ListNode* newnode = BuyListNode(x);
tail->next = newnode;
newnode->prev = tail;
newnode->next = pHead;
pHead->prev = newnode;
}
2.3双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
printf("<=head=>");
while (cur != pHead)
{
printf("%d<=>", cur->data);
cur = cur->next;
}
printf("\n");
}
在这里说下,为什么一些指针有必要断言,一些没必要?如果一个指针可以是NULL,也可以不是NULL,此时不用断言,比如我们传一个空链表给尾插函数,就可以断言,因为我们要插入元素。如果一个指针不可能为NULL,这时就得断言,可以有效地防止一些错误,比如不小心传NULL给函数。
2.4双向链表尾插
bool LTempty(ListNode* pHead)
{
return pHead->next == pHead;//为真,返回1,为假,返回0
}
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(!LTempty(pHead));
ListNode* Tail = pHead->prev;
ListNode* PrevTail = pHead->prev->prev;
pHead->prev = PrevTail;
PrevTail->next = pHead;
free(Tail);
Tail = NULL;
}
2.5双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyListNode(x);
newnode->next = pHead->next;
pHead->prev = newnode;
newnode->prev = pHead;
pHead->next = newnode;
}
2.6双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(!LTempty(pHead));
ListNode* First = pHead->next;
ListNode* NextFirst = First->next;
pHead->next = NextFirst;
NextFirst->prev = pHead;
free(First);
First = NULL;
}
2.7双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->next ;
while (cur != pHead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
2.8双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* newnode = BuyListNode(x);
ListNode* PrevPos = pos->prev;
newnode->next = pos;
pos->prev = newnode;
PrevPos->next = newnode;
newnode->prev = PrevPos;
}
2.9双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{
assert(pos);
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
pos = NULL;
}
2.10双向链表销毁
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next;
while (cur!=pHead)
{
ListNode* next = cur->next;
free(cur);
cur = next;
}
free(pHead);
pHead = NULL;
}
3.测试