链表的基本操作
2018-03-29 10:28
225 查看
对单向的不带环不带头节点的链表做以下操作:
注意:对链表操作时要看传入的是一级指针还是二级指针,修改头指针的指向用二级指针,其他用一级指针。
linklist.h //单向的不带环不带头节点的链表 #pragma once typedef char LinkNodeType; typedef struct LinkNode { LinkNodeType data; struct LinkNode *next; }LinkNode; typedef LinkNode* PLinkNode; void LinkListInit(PLinkNode*); //初始化 void LinkListDestroy(PLinkNode*); //销毁 void LinkListPushBack(LinkNode** head,LinkNodeType value); //尾插 void LinkListPopBack(LinkNode** head); //尾删 void LinkListPushFront(LinkNode** head,LinkNodeType value); //头插 void LinkListPopFront(LinkNode** head); //头删 //将一个元素插入到pos之后 void LinkListInsert(LinkNode* pos,LinkNodeType value); //将一个元素插入到pos之前 void LinkListInsertBefore(LinkNode** head,LinkNode* pos,LinkNodeType value); //优化后将元素插入到pos之前 void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value); //删除元素 void LinkListErase(LinkNode** head,LinkNode* pos); //优化后的删除 void LinkListErase2(LinkNode** head,LinkNode* pos); //给一个元素找位置 LinkNode* LinkListFind(LinkNode* head,LinkNodeType to_find); //判断链表是否为空,链表为空返回1,否则,返回0 int LinkListEmpty(LinkNode* head); //求链表元素的个数 int LinkListSize(LinkNode* head); //删除指定值的元素 void LinkListRemove(LinkNode** head,LinkNodeType value); //删除指定值的所有元素 void LinkListRemoveAll(LinkNode** head,LinkNodeType value);
linklist.c #include"linklist.h" #include<stdio.h> #include<stdlib.h> LinkNode* CreateNode(LinkNodeType value)//创建节点 { LinkNode* new_node =(LinkNode *)malloc(sizeof(LinkNode)); new_node->data = value; new_node->next = NULL; return new_node; } void DestroyNode(LinkNode* node)//销毁节点 { free(node); } void LinkListInit(PLinkNode* node)//链表初始化 { *node = NULL; } void LinkListDestroy(LinkNode** phead)//销毁链表 { if(phead == NULL) return; //非法输入 if(*phead == NULL) return; //空链表 LinkNode* cur = *phead; while(cur != NULL) { LinkNode* to_delete = cur; cur = cur->next; DestroyNode(to_delete); } *phead = NULL; } void LinkListPushBack(LinkNode** phead,LinkNodeType value)//尾插 { if(phead == NULL) return; //非法输入 if(*phead == NULL) { //空链表 *phead = CreateNode(value); return; } //链表非空 LinkNode* cur = *phead; while(cur->next != NULL) { cur = cur->next; } LinkNode* new_node = CreateNode(value); cur->next = new_node; } void LinkListPopBack(LinkNode** phead)//尾删 { if(phead ==NULL) return; //非法输入 if(*phead == NULL) return; //单链表 if((*phead)->next == NULL) { //链表只有一个元素 DestroyNode(*phead); *phead = NULL; return; } LinkNode* cur = *phead; LinkNode* pre = NULL; while(cur->next != NULL) { 4000 pre = cur; cur = cur->next; } pre->next = NULL; DestroyNode(cur); return; } void LinkListPushFront(LinkNode** phead,LinkNodeType value)//头插 { if(phead == NULL) return; //非法输入 LinkNode* new_node = CreateNode(value); new_node->next = *phead; *phead = new_node; } void LinkListPopFront(LinkNode** phead)//头删 { if(phead == NULL) return; //非法输入 if(*phead == NULL) return; //空链表 LinkNode* to_erase = *phead; *phead = (*phead)->next; DestroyNode(to_erase); return; } void LinkListInsert(LinkNode* pos,LinkNodeType value)//在pos后面插入一个新节点 { if(pos == NULL) return; //非法输入,pos表示一个节点的指针 //如果pos为空,说明根本不存再这样的节点 LinkNode* new_node = CreateNode(value); new_node->next = pos->next; pos->next = new_node; return; } void LinkListInsertBefore(LinkNode** phead,LinkNode* pos,LinkNodeType value)//在pos前面插入一个新节点 { if(phead == NULL ||pos == NULL) return; //非法输入 if(pos == *phead) { //要插的地方刚好是头节点 LinkListPushFront(phead,value); return; } LinkNode* cur = *phead; for( ;cur != NULL;cur = cur->next) { if(cur->next == pos) { break; //跳出循环时cur刚好是pos的前一个节点 } } if(cur == NULL) { return; } LinkListInsert(cur,value); } //我们可以看到在pos前面插入新节点时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n); //而下面这种算法,通过交换pos位置和新插入节点的数据的方法可以达到同样的目的,时间复杂度为O(1). void LinkListInsertBefore2(LinkNode* pos,LinkNodeType value) { if(pos == NULL) { return; //非法输入 } LinkListInsert(pos,pos->data); pos->data = value; //交换新插入的节点和pos的位置 } void LinkListErase(LinkNode** phead,LinkNode* pos)//删除 { if((phead == NULL)||(pos == NULL)) return; //非法输入 if(*phead == NULL) return; //空链表 if(*phead == pos) LinkListPopFront(phead);//如果pos是起始位置,调用头删 LinkNode* cur = *phead; for( ;cur != NULL;cur = cur->next) { if(cur->next == pos) { cur->next = pos->next; pos->next = NULL; DestroyNode(pos); } } return; } //删除pos位置时,需要遍历链表,找到它的前一个节点,这种算法时间复杂度为O(n); //而下面这种算法,将pos->next的数据赋给pos然后删除pos->next节点的方法可以达到同样的目的,时间复杂度为O(1). void LinkListErase2(LinkNode** phead,LinkNode* pos) { if((phead == NULL)||(pos == NULL)) return; //非法输入 if(*phead == NULL) return; //空链表 pos->data = pos->next->data; LinkNode* to_erase = pos->next; pos->next = to_erase->next; DestroyNode(to_erase); return; } LinkNode* LinkListFind(LinkNode* phead,LinkNodeType to_find)//找指定元素的位置 { if(phead == NULL) return NULL; //空链表 LinkNode* cur = phead; while(cur != NULL) { if(cur->data == to_find) { return cur; } cur = cur->next; } return NULL; } int LinkListEmpty(LinkNode* phead)//判断链表是否为空 { if(phead == NULL) { return 1; //空链表 } else { return 0; } } int LinkListSize(LinkNode* phead)//求链表大小 { if(phead == NULL) return; //空链表 LinkNode* cur = phead; size_t count = 0; for( ;cur != NULL;cur = cur->next) { count++; } return count; } void LinkListRemove(LinkNode** phead,LinkNodeType value)//移除指定值的元素 { if(phead == NULL) return; //非法输入 if(*phead == NULL) return; //空链表 LinkNode* cur = LinkListFind(*phead,value); if(cur == NULL) { return; //没找到 } LinkListErase(phead,cur); } void LinkListRemoveAll(LinkNode** phead,LinkNodeType value)//移除指定值的所有元素 { if(phead == NULL) return; //非法输入 if(*phead == NULL) return; //空链表 while(1) { LinkNode* cur = LinkListFind(*phead,value); if(cur == NULL) { return; } LinkListErase(phead,cur); } } /////////////////////////// //以下是测试代码 /////////////////////////// #include<stdio.h> #define TEST_HEADER printf("\n=====================%s====================\n",__FUNCTION__) void LinkListPrintChar(LinkNode* head,const char* msg) { printf("[%s]\n",msg); LinkNode* cur = head; for( ;cur != NULL;cur = cur->next) { printf("[%c|%p] ",cur->data,cur); } printf("\n"); } void TestInit() { TEST_HEADER; LinkNode* head; LinkListInit(&head); } void TestPushBack() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListPrintChar(head,"尾插四个元素"); } void TestPopBack() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPopBack(&head); LinkListPrintChar(head," 对空链表尾删"); LinkListPushBack(&head,'a'); LinkListPopBack(&head); LinkListPrintChar(head,"对只有一个元素的链表尾删"); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListPopBack(&head); LinkListPopBack(&head); LinkListPrintChar(head,"尾删两个元素"); LinkListPopBack(&head); LinkListPopBack(&head); LinkListPrintChar(head,"再尾删两个元素"); } void TestPushFront() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPushFront(&head,'a'); LinkListPushFront(&head,'b'); LinkListPushFront(&head,'c'); LinkListPushFront(&head,'d'); LinkListPrintChar(head,"头插四个元素"); } void TestPopFront() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPopFront(&head); LinkListPrintChar(head,"对空链表头删"); LinkListPushFront(&head,'a'); LinkListPushFront(&head,'b'); LinkListPushFront(&head,'c'); LinkListPushFront(&head,'d'); LinkListPrintChar(head,"头插四个元素"); LinkListPopFront(&head); LinkListPopFront(&head); LinkListPrintChar(head,"头删两个元素"); LinkListPopFront(&head); LinkListPopFront(&head); LinkListPrintChar(head,"再头删两个元素"); } void TestInsert() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos = head->next; LinkListInsert(pos,'x'); LinkListPrintChar(head,"插入'x'元素"); } void TestInsertBefore() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos1 = head; LinkListInsertBefore(&head,pos1,'x'); LinkListPrintChar(head,"向头节点之前插入'x'元素"); LinkNode* pos2 = head->next->next; LinkListInsertBefore(&head,pos2,'y'); LinkListPrintChar(head,"向'b'之前插入'y'元素"); } void TestInsertBefore2() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos1 = head; LinkListInsertBefore(&head,pos1,'x'); LinkListPrintChar(head,"向头节点之前插入'x'元素"); LinkNode* pos2 = head->next->next; LinkListInsertBefore(&head,pos2,'y'); LinkListPrintChar(head,"向'b'之前插入'y'元素"); } void TestErase() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListErase(&head,(LinkNode*)0x11); LinkListPrintChar(head,"尝试对空链表删除"); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos= head; LinkListErase(&head,pos); LinkListPrintChar(head,"删除元素'a'"); LinkNode* pos2 = (LinkNode*)0x10; LinkListErase(&head,pos2); LinkListPrintChar(head,"尝试对一个不存在的位置删除"); } void TestErase2() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListErase(&head,(LinkNode*)0x11); LinkListPrintChar(head,"尝试对空链表删除"); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos = head->next; LinkListErase(&head,pos); LinkListPrintChar(head,"删除元素'b'"); LinkNode* pos2 = (LinkNode*)0x10; LinkListErase(&head,pos2); LinkListPrintChar(head,"尝试对一个不存在的位置删除"); } void TestFind() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkNode* pos = LinkListFind(head,'a'); printf("'a'的地址是:%p\n",pos); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkNode* pos1 = LinkListFind(head,'c'); printf("'c'的地址是:%p\n",pos1); LinkNode* pos2 = LinkListFind(head,'x'); printf("'x'的地址是:%p",pos2); } void TestEmpty() { TEST_HEADER; LinkNode* head; LinkListInit(&head); size_t cur1 = LinkListEmpty(head); printf("%d\n",cur1); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); size_t cur2 = LinkListEmpty(head); printf("%d",cur2); } void TestSize() { TEST_HEADER; LinkNode* head; LinkListInit(&head); size_t cur1 = LinkListSize(head); printf("%d\n",cur1); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); size_t cur2 = LinkListSize(head); printf("%d",cur2); } void TestRemove() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListRemove(&head,'a'); LinkListPrintChar(head,"尝试对空链表删除"); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'d'); LinkListRemove(&head,'a'); LinkListPrintChar(head,"删除元素'a'"); LinkListRemove(&head,'x'); LinkListPrintChar(head,"尝试删除一个不存在的值"); } void TestRemoveAll() { TEST_HEADER; LinkNode* head; LinkListInit(&head); LinkListRemoveAll(&head,'a'); LinkListPrintChar(head,"尝试对空链表删除"); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'b'); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'c'); LinkListPushBack(&head,'a'); LinkListPushBack(&head,'d'); LinkListPushBack(&head,'a'); LinkListRemoveAll(&head,'a'); LinkListPrintChar(head,"删除元素'a'"); LinkListRemoveAll(&head,'x'); LinkListPrintChar(head,"尝试删除一个不存在的值"); } int main() { TestInit(); TestPushBack(); TestPopBack(); TestPushFront(); TestPopFront(); TestInsert(); TestInsertBefore(); TestInsertBefore2(); TestErase(); TestErase2(); TestFind(); TestEmpty(); TestSize(); TestRemove(); TestRemoveAll(); printf("\n"); return 0; }
注意:对链表操作时要看传入的是一级指针还是二级指针,修改头指针的指向用二级指针,其他用一级指针。