链表
1. 链表的定义
1 2 3 4 5 6 7
| typedef int SLTDateType; //数据类型别名定义
typedef struct SListNode { SLTDateType data; //data用来储存数据 struct SListNode* next; //定义next指针用来链接 }SLTNode;
|
2. 创建节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| SLTNode* BuyListNode(SLTDateType x) { SLTNode* newnode =(SLTNode*)malloc(sizeof(SLTNode)); if(newnode == NULL) { printf("malloc fall\n"); exit(-1); }
newnode->data = x; newnode->next = NULL;
return newnode; };
|
3. 打印链表
1 2 3 4 5 6 7 8 9
| void SListPrint(SLTNode* phead){ SLTNode* cur = phead; while (cur != NULL) { printf("%d",cur->data); cur = cur->next; } printf("\n"); };
|
4. 尾插
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void SListPushBack (SLTNode** pphead,SLTDateType x){ //传二级指针,通过改变形参来改变实参 assert(*pphead != NULL); SLTNode* newnode = BuyListNode(x); if(*pphead == NULL) { *pphead = newnode; //如果头指针为空,直接让头指针指向新结点 } else { SLTNode* tail = *pphead; while (tail->next != NULL) //找尾 { tail = tail->next; } tail->next = newnode; //把尾结点接上新结点 } };
|
5. 头插
1 2 3 4 5 6
| void SListPushFront (SLTNode** pphead,SLTDateType x){ assert(*pphead != NULL); SLTNode* newnode = BuyListNode(x); newnode->next = *pphead; //新结点的next指向之前的头 *pphead = newnode; //再把头指针前移 };
|
6. 尾删
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void SListPopBack(SLTNode** pphead){ assert(*pphead != NULL); //判断是否有数据可删 if((*pphead)->next == NULL) //如果链表只有一个结点 { free(*pphead); *pphead = NULL; } else { SLTNode* prev = NULL; //定义一个新的指针,来保存移动之前的地址 SLTNode* tail = *pphead; while (tail->next != NULL)//找尾,且保存尾之前的结点位置到prev { prev = tail; tail = tail->next; } free(tail); tail = NULL; prev->next = NULL; //删除尾节点,并且给新的尾节点next指针赋上空 } };
|
7. 头删
1 2 3 4 5 6 7
| void SListPopFront(SLTNode** pphead) { assert(*pphead != NULL); SLTNode* prev = (*pphead)->next; //定义一个指针指向头节点后面那个节点 free(*pphead); //删除头节点 *pphead = prev; //将头指针指向新的头节点 };
|
8. 查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| SLTNode* SListFind(SLTNode* phead,SLTDateType x) { assert(phead != NULL); SLTNode* cur = phead; while (cur) { if(cur->data == x) { return cur; } else { cur = cur->next; } } return NULL; };
|
9. 在pos位置之前去插入一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void SListInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x) { assert(*pphead != NULL); assert(pos != NULL); SLTNode* newnode =BuyListNode(x); if (*pphead == pos) //如果pos位置为头节点位置 { newnode->next = *pphead; *pphead = newnode; } else { SLTNode* posPrev = *pphead; while (posPrev->next != pos) //找到pos位置的前一个节点位置,储存到posPrev里面 { posPrev = posPrev->next; } posPrev->next = newnode; newnode->next = pos; } }
|
10. 在pos位置之后去插入一个节点
1 2 3 4 5 6 7
| void SListInsertAfter(SLTNode* pos,SLTDateType x) { assert(pos != NULL); SLTNode* newnode = BuyListNode(x); newnode->next = pos->next; //必须先让新节点的next先指向后面结点 pos->next = newnode; //再让pos的next指向新结点 };
|
11. 删除pos位置节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void SListErase(SLTNode** pphead,SLTNode* pos) { assert(*pphead != NULL); assert(pos != NULL); if(*pphead == pos) //如果pos位置是头节点 { *pphead = pos->next; free(pos); } else { SLTNode *prev = *pphead; //找到pos位置的前一个节点位置,储存到prev里面 while (prev->next != pos) { prev = prev->next; } prev->next = pos->next; //将pos位置前一个节点和pos位置后一个节点链接 free(pos); } };
|
12. 删除pos位置的后面一个节点
1 2 3 4 5 6 7 8
| void SListEraseAfter(SLTNode* pos) { assert(pos !=NULL); assert(pos->next != NULL); //如果pos为尾节点 SLTNode* prev = pos->next; pos->next = prev->next; free(prev); };
|
13. 链表的销毁
1 2 3 4 5 6 7 8 9 10 11 12
| void SListDestory(SLTNode** pphead) { assert(*pphead != NULL); SLTNode* cur = *pphead; while (cur) //依次释放节点 { SLTNode* prev = cur->next; free(cur); cur = prev; } *pphead = NULL; //头指针赋空 };
|
14. 单链表的优缺点
1. 优点
(1)存储空间动态分配,只要有内存空间,数据就不会溢出。
(2)便于实现插入与删除操作。
2. 缺点
(1)存储空间不一定连续,内容分散,有时会导致调试不便。
(2)每一个结点(除头结点)都有数据域与指针域,增大存储空间的开销。
(3)单链表查找结点时,需要从头开始查找,增加查找时间。