链表的简介
链表:物理存储结构非连续,通过指针将链表的每一个节点联系起来。(可以类比火车)
链表有很多分类,带头的链表,单向链表与双向链表,今天要讲解和实现的是单向链表,也是使用很频繁的一种数据结构。
重点知识的讲解:指针存储的是地址,当然可以存储结构体的地址,而访问结构体中的元素要做的是->访问结构体中的数据以及下一个节点。 要修改结构体中的一些值,仅仅一级指针就可以。 如果要修改指针的存储的值,在一个函数中,形式参数仅仅只是实际参数的一份拷贝,因此你需要修改指针的值时,需要调用二级指针。 这个相当难点理解,如果能够画图深入分析很有帮助。
有了以上的了解的话,当链表只有一个节点或者是没有节点的状态,就需要的是二级指针,去修改一级指针存储的地址,而不是一级指针要去修改节点的值。 一下是实现过程:
头文件 Linked_List.h实现:
#include<stdio.h> #include<stdlib.h> //定义值,与节点 typedef int SLTDateType; typedef struct SListNode { SLTDateType data; struct SListNode* next; }SListNode ;
要实现的功能:
//动态申请一个节点 SListNode* CreateSListNode(SLTDateType X); //单链表的打印 void SListPrint(SListNode* plist); //尾部插入 void SListPushBack(SListNode** pplist, SLTDateType x); //头部插入 void SListPushFront(SListNode** pplist, SLTDateType x); //尾部删除 void SListPopBack(SListNode** pplist); //头部删除 void SListPopFront(SListNode** pplist); //链表的查找 SListNode* SListFind(SListNode* plist, SLTDateType x); //在pos位置之后插入x,pos(为给定的y的值的位置) void SListInsertAfter(SListNode* plist, SLTDateType x,SLTDateType y); //删除第一个y值后面的节点 void SListEraseAfter(SListNode* plist, SLTDateType y);
注意的逻辑实现部分 realize.c 实现:
一定注意一级指针与二级指针的使用。
#include "Linked_List.h" //创造一个节点 SListNode* CreateSListNode(SLTDateType x) { SListNode* newnode = (SListNode*)malloc(sizeof(SListNode)); if (newnode == NULL) { perror("malloc failed"); return; } newnode->data = x; newnode->next = NULL; return newnode; } //单链表的打印 void SListPrint(SListNode* plist) { while (plist != NULL) { printf("%d-> ", plist->data); plist = plist->next; } printf("NULL\n"); } //头部插入 //形参是实参的拷贝,改变了形参并不会改变实参,所以用二级指针 void SListPushFront(SListNode** pplist,SLTDateType x) { SListNode*cur = CreateSListNode(x); cur->next = * pplist; *pplist = cur; } //头部删除 void SListPopFront(SListNode** pplist) { if (*pplist == NULL) return; SListNode* cur = (*pplist)->next; free(*pplist); *pplist = cur; } //尾部插入 void SListPushBack(SListNode** pplist, SLTDateType x) { SListNode* newnode = CreateSListNode(x); if (*pplist == NULL) { *pplist = newnode; } else { SListNode* cur = *pplist; while (cur->next != NULL) { cur = cur->next; } cur->next = newnode; } } //尾部删除 void SListPopBack(SListNode** pplist) { SListNode* cur = *pplist; if(cur == NULL) return; if (cur->next == NULL) { free(cur); cur = NULL; *pplist = NULL; } else { while ( cur->next->next != NULL) { cur = cur->next; } free(cur->next); cur->next = NULL; } } //链表的查找 SListNode* SListFind(SListNode* plist, SLTDateType x) { if (plist == NULL) return; SListNode* cur = plist; int count = 0; while (cur!=NULL) { if (cur->data == x) { return cur; } count++; cur = cur->next; } printf("Not Find"); return; } //在数据y位置之后插入x void SListInsertAfter(SListNode* plist, SLTDateType x, SLTDateType y) { SListNode* pos = SListFind(plist, x); SListNode* cur = CreateSListNode(y); if (pos->next != NULL) { cur->next = pos->next; } pos->next = cur; } //删除第一个y值后面的节点 void SListEraseAfter(SListNode* plist, SLTDateType y) { SListNode* pos = SListFind(plist, y); if (pos->next == NULL) return; SListNode* cur = pos->next; pos->next = pos->next->next; free(cur); cur == NULL; }
测试样例的给出,test.c文件:
#include "Linked_List.h" void test1() { SListNode* SL = NULL; SListPushFront(&SL, 1); SListPushFront(&SL, 2); SListPushFront(&SL, 3); SListPushFront(&SL, 4); SListPushFront(&SL, 5); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPopFront(&SL); SListPrint( SL ); } void test2() { SListNode* SL = NULL; SListPushBack(&SL, 1); SListPushBack(&SL, 2); SListPushBack(&SL, 3); SListPushBack(&SL, 3); SListPushBack(&SL, 2); SListPrint(SL); } void test3() { SListNode* SL = NULL; SListPushBack(&SL, 1); SListPushBack(&SL, 2); SListPushBack(&SL, 3); SListPopBack(&SL); SListPopBack(&SL); SListPopBack(&SL); SListPopBack(&SL); SListPrint(SL); } void test4() { SListNode* SL = NULL; SListPushBack(&SL, 1); SListPushBack(&SL, 2); SListPushBack(&SL, 3); SListNode* p = SListFind(SL,2); printf("%d ", p->data); //SListPrint(SL); } void test5() { SListNode* SL = NULL; SListPushBack(&SL, 1); SListPushBack(&SL, 2); SListPushBack(&SL, 3); SListInsertAfter(SL, 4, 4); SListPrint(SL); } void test6() { SListNode* SL = NULL; SListPushBack(&SL, 1); SListPushBack(&SL, 2); SListPushBack(&SL, 3); SListEraseAfter(SL, 1); SListPrint(SL); } int main() { /*test1(); test2();*/ //test3(); //test4(); //test5(); //test6(); return 0; }
总结
debug与画图一定要亲自尝试,不要去照抄代码,要带有自己的思考,可以先模仿,但是最后一定要有能力实现全部功能。