数据结构(链表)(2)
- 由于链表这部分的内容, 比较难讲, 所以打算分4节给大家讲完, 这节呢主要就是实现4个最主要的函数:
- 也就是尾部插入, 头部插入, 尾部删除和头部删除. 链表这部分, 说难不难, 说简单不简单, 对于刚刚开始接触链表的同学可能得多看几遍, 结合我的图解, 还有文字讲解, 好好的想一想还是能理解的.
- 咱们最开始实现的是一个“无头, 单向, 非循环 ”的简单链表, 别的形式的链表会在最后和大家讲解.
- 那么就开始今天的硬菜了, 实现链表尾部插入数据的这个功能. 不过在实现这个功能之前得写个简单的功能函数. 因为咱们链表的节点空间是得要动态开辟的, 因为各种插入都要用到这个功能, 那么就先写一个创建新节点的这么一个功能的函数.
//动态申请一个节点 SLTNode* BuySListNode(SLDatatype x) { //动态开辟一个节点的结构体空间 SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode)); //判断有没有创建成功 if (newnode == NULL) { perror("malloc failed"); exit(-1); } //创建成功之后就赋值 newnode->data = x; newnode->next = NULL; //返回结构体指针 return newnode; }
- 这个函数的名字大家随便怎么取都可以, 不过呢, 大部分都是这么叫的, 大家按照我这样写也可以. 在上一节也着重讲了链表节点的一个结构, 不熟悉的可以再看看上一节. 下面也补充一下等会我们会用到的打印函数, 主要是拿来测试用的. 这个函数的具体讲解也在上一节有详细的说明了.
//循环遍历打印链表 void PrintSList(SLTNode* phead) { //把头结点的值赋给临时变量cur,不要用phead来遍历, //因为等会可能还会用到phead,结果被改了,就不好弄了. SLTNode* cur = phead; while (cur != NULL) { printf("%d->", cur->data); cur = cur->next; } printf("NULL\n"); }
- OK, 那就开始实现尾插功能这个函数了, 我先画图给大家讲讲.
- 所以尾部插入的代码如下: (两种情况结合起来就是下面这样, 因为虽然要传的参数不同, 但是二级指针可以通过解引用变成一级指针, 所以不影响. )
void SLTPushBack(SLTNode** pphead, SLTDataType x) { assert(pphead); SLTNode* newnode = SLTBuyNode(x); //链表为空,新节点作为phead if (*pphead == NULL) { *pphead = newnode; return; } //链表不为空,找尾节点 SLTNode* ptail = *pphead; while (ptail->next) { ptail = ptail->next; } //ptail就是尾节点 ptail->next = newnode; }
- 那么接下来就是头部插入数据了, 代码直接如下:
void SLTPushFront(SLTNode** pphead, SLTDataType x) { SLTNode* newnode = BuySListNode(x); newnode->next = *pphead; *pphead = newnode; }
- 接下来是尾部删除数据的代码:
void SLTPopBack(SLTNode** pphead) { // 1、判空,空的时候就不能删除,因为没有节点可以删除 assert(*pphead); // 2、一个节点 if ((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; } // 3、一个以上节点 else { //两种方法,这个方法和下面那个方法都可以 //SLTNode* tailPrev = NULL; //SLTNode* tail = *pphead; //while (tail->next) //{ // tailPrev = tail; // tail = tail->next; //} //free(tail); tail = NULL; //tailPrev->next = NULL; SLTNode* tail = *pphead; while (tail->next->next) { tail = tail->next; } free(tail->next); tail->next = NULL; } }
- 最后就是头部删除的代码:
void SLTPopFront(SLTNode** pphead) { // 空 assert(*pphead); // 非空 SLTNode* newhead = (*pphead)->next; free(*pphead); *pphead = newhead; }