您的位置:首页 > 理论基础 > 数据结构算法

数据结构第二天、线性表的链式表示和实现

2015-07-10 17:40 531 查看
  今天是学习数据结构的第二天,让我们来一起重温数据结构中极为经典的链表。

  在复习链表之前我们来复习一个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空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: