赞
踩
目录
- typedef int LTDataType;
- typedef struct ListNode
- {
- struct ListNode* next;
- struct ListNode* prev;
- LTDataType data;
- }ListNode;
使用typedef:如果一开始我们就确定了结构体中的变量类型,后续在项目过程中如果需要对这个变量类型进行调整,那么所需的操作是很繁琐的。故使用typedef,后续若是需要修改,改动typedef就足够了。
- ListNode* BuyListNode(LTDataType x)
- {
- ListNode* node = (ListNode*)malloc(sizeof(ListNode));
- if (node == NULL)
- {
- perror("错误原因:");
- exit(-1);
- }
- node->data = x;
- node->next = NULL;
- node->prev = NULL;
- return node;
- }
不需要二级指针是因为其带了哨兵位的头结点
- ListNode* ListInit()
- {
- ListNode* phead = BuyListNode(0);
- phead->next = phead;
- phead->prev = phead;
- return phead;
- }
尾插先找尾,而phead的prev为尾
- void ListPushBack(ListNode* phead, LTDataType x)
- {
- assert(phead);
-
- ListNode* tail = phead->prev;
- ListNode* newnode = BuyListNode(x);
-
- //原来尾结点和现在新结点链接
- tail->next = newnode;
- newnode->prev = tail;
-
- //新结点和头结点链接
- newnode->next = phead;
- phead->prev = newnode;
- }
如果只插入一个结点是否需要改正上述代码?不需要
注意循环终止的条件
- void ListPrint(ListNode* phead)
- {
- ListNode* cur = phead->next;
- while (cur != phead)
- {
- printf("%d", cur->data);
- cur = cur->next;
- }
- printf("\n");
- }
- void ListPushFront(ListNode* phead, LTDataType x)
- {
- assert(phead);
- ListNode* first = phead->next;
- ListNode* newnode = BuyListNode(x);
-
- phead->next = newnode;
- newnode->prev = phead;
-
- newnode->next = first;
- first->prev = newnode;
- }
用头插法只插入一个结点是否可行?可行
- void ListNodePopBack(ListNode* phead)
- {
- assert(phead);
- ListNode* tail = phead->prev;
- ListNode* tailPrev = tail->prev;
- free(tail);
-
- tailPrev->next = phead;
- phead->prev = tailPrev;
- }
只有一个结点时(非头结点)是否可用上述代码?进入free循环时头结点会被删除
改正:加一步判断 assert(phead->next != phead);
- void ListNodePopFront(ListNode* phead)
- {
- assert(phead);
- assert(phead->next != phead);
- ListNode* first = phead->next;
- ListNode* second = first->next;
-
- free(first);
-
- phead->next = second;
- second->prev = phead;
- }
- 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;
-
- }
- void ListInsert(ListNode* pos, LTDataType x)
- {
- assert(pos);
-
- ListNode* prev = pos->prev;
- ListNode* newnode = BuyListNode(x);
-
- prev->next = newnode;
- newnode->prev = prev;
-
- newnode->next = pos;
- pos->prev = newnode;
- }
pos为头和尾代码能否运行?若x = 4
相当于尾插(在phead前面插入一个结点)
由此,尾插法的代码可改为
ListInsert(phead,x);
头插法可改为
ListInsert(phead->next,x);
- void ListErase(ListNode* pos )
- {
- assert(pos);
-
- ListNode*prev = pos->prev;
- ListNode*next = pos->next;
-
- prev->next = next;
- next->prev = prev;
-
- free(pos);
- }
由此,尾删除法可改为
ListErase(phead->prev);
头删法可改为
ListErase(phead->next)
- int ListEmpty(ListNode* phead)
- {
- assert(phead);
- return phead->next == phead ? 1 : 0;
- }
- int ListSize(ListNode* phead)
- {
- assert(phead);
- int size = 0;
- ListNode* cur = phead->next;
- while (cur != phead)
- {
- ++size;
- cur = cur->next;
- }
- return size;
- }
- void ListDestory(ListNode* phead)
- {
- assert(phead);
-
- ListNode* cur = phead->next;
- while (cur != phead)
- {
- ListNode* next = cur->next;//提前保存它的下一个
- //ListErase(cur);
- free(cur);
- cur = next;
- }
- free(phead);
- //phead = NULL;
- }
使用函数的时候注意将野指针置(或者用二级指针,因为传一级指针时函数内部的置空不起作用)
ListDestory(plist);
plist = NULL;
不同点 | 顺序表 | 链表 |
存储空间上 | 物理上连续 | 逻辑上连续,但物理上不连续 |
随机访问 | 支持O(1) | 不支持:O(N) |
任意位置插入或者删除元素 | 可能需要搬移元素,效率低,O(N) | 只需修改指针指向 |
插入 | 动态顺序表,空间不够时需要扩容 | 没有容量的概念 |
应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
缓存利用率 | 高 | 低 |
优点 | 1.按下标去进行随机访问 2、cpu高速缓存命中率比较高 | 1.按需申请内存,需要存一个数据就申请一块内存 2.任意位置插入和删除数据效率高,O(1) |
缺点 | 1.空间不够需要增容(一定程序的性能消耗)可能存在一定的空间浪费 2、头部或者中间插入删除数据需要挪动数据,O(N) | 不支持下标的随机访问 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。