今天是学习数据结构的第二天,让我们来一起重温数据结构中极为经典的链表。
在复习链表之前我们来复习一个C/C++中很重要的知识点
#include <stdio.h> #include <stdlib.h> typedef char ElemType; typedef struct node { ElemType data; struct node *next; }LinkList; void InitList(LinkList *L)//初始化单链表 { L=(LinkList *)malloc(sizeof(LinkList)); L->next=NULL; } int main() { int i; ElemType e; LinkList *L; InitList(L); }
很多同学会说上述代码不就是完成链表初始化的一段代码吗,没有什么特殊的。其实,这段代码是会报错的。因为它根本没有初始化链表。
原因是InitList(L)实际上是对值的传递,和swap()函数的原理类似,传值调用传递的时原来数据的副本,副本是在栈上调用的,在函数执行完成后会自动释放,也没有返回到main函数的具体值,所以会失败。
正确方法是下面这种方法
#include <stdio.h> #include <stdlib.h> typedef char ElemType; typedef struct node { ElemType data; struct node *next; }LinkList; void InitList(LinkList **L)//初始化单链表 { *L=(LinkList *)malloc(sizeof(LinkList)); (*L)->next=NULL; } int main() { int i; ElemType e; LinkList *L; InitList(&L); }
也就是传入指针的地址,即指针的指针。
在我的代码中,我才去了另外一种方法,即初始化函数返回时将指针赋值给main函数里的局部变量,这样也可以解决这种问题,具体代码如下:
#include <stdio.h> #include <stdlib.h> typedef struct Node { int Data; struct Node *Next; } List; //创建具有头结点的链表 List *CreateList(int n) { List *LinkList = (List *)malloc(sizeof(List)); LinkList->Next = NULL; for (int i = n; i > 0; --i) { List *p = (List *)malloc(sizeof(List)); scanf("%d", &p->Data); p->Next = LinkList->Next; LinkList->Next = p; } return LinkList; } //添加 void Insert(List *LinkList, int n, int e) { List *p = LinkList; int j = 0; while (p && j < n-1) { p = p->Next; ++j; } if (!p || j > n-1) { printf("Error\n"); return; } List *s = (List *)malloc(sizeof(List)); s->Data = e; s->Next = p->Next; p->Next = s; return; } //删除 void Delete(List *LinkList, int n) { List *p = LinkList; int j = 0; while (p->Next && j < n-1) { p = p->Next; ++j; } if (p->Next == NULL || j > n-1) { printf("Error\n"); return; } List *q = p->Next; p->Next = q->Next; free(q); return; } //已知单链线性表La和Lb的元素按值非递减排列 //归并La和Lb得到新的单链线性表Lc,Lc也按值非递减排列 List *MergeList(List *la, List *lb) { List *pa = la->Next; List *pb = lb->Next; List *lc = la; List *pc = lc; while (pa && pb) { if (pa->Data <= pb->Data) { pc->Next = pa; pc = pa; pa = pa->Next; } else { pc->Next = pb; pc = pb; pb = pb->Next; } } pc->Next = pa?pa:pb; free(lb); return la; } //遍历 void Traverse(List *LinkList) { List *q = LinkList->Next; while (q != NULL) { printf("%d\n", q->Data); q = q->Next; } return; } int main(int argc, char const *argv[]) { List *list_link; list_link = CreateList(4); printf("输出创建的链表\n"); Traverse(list_link); //printf("%d\n", list_link->Next->Data); printf("输出删除具体节点后的链表\n"); Delete(list_link, 2); Traverse(list_link); printf("输出la,lb归并后的链表测试\n"); List *la, *lb, *lc; printf("请输入la链表\n"); la = CreateList(3); printf("请输入lb链表\n"); lb = CreateList(4); lc = MergeList(la, lb); Traverse(lc); return 0; }
Insert()和Delete()的时间复杂度也都是O(n)量级的。
还有一个要主要的点是在做MergeList(归并操作)时,Lc链表只是将La和Lb链表中的节点重新链接在一起了,没有重新malloc空间。
时间: 2024-10-06 14:21:58