数据结构c语言版线性表和链表,数据结构(C语言) —— 线性表(链表)

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

上一篇博客我们详细的讲述了顺序表的实现,但以讲述的形式来记录数据结构这部分的笔记效率实在是有些低,所以接下来的部分我就单纯地列出知识点就完事了。嘻嘻嘻!~

单链表

单链表结点的结构体:typedef struct Node

{

DataType data;

struct Node *next;

} SLNode;

其中,data域用来存放数据元素,next域用来存放指向下一结点的指针。

单链表还分为带头结点结构和不带头结点结构两种。我们把指向单链表的指针称作头指针,头指针所指的不存放数据元素的第一个结点称作头结点。我们一般构造带头结点的单链表(以下讲解的也是带头结点的单链表)。

单链表的操作实现

1.C语言的动态申请内存空间函数

要知道,单链表中的每一个结点,是在需要时才向系统申请的,这称作动态内存空间申请。动态申请的内存空间,当不再需要时,必须手动释放。C语言提供了动态申请内存空间的函数malloc()和动态释放函数内存空间的函数free()。这些函数包含在头文件malloc.h中。void *malloc(unsigned size);

-> 向系统动态申请size个字节的内存单元空间,函数返回值为所申请内存空间的首地址。

void free(void *p);

-> p为内存空间首地址指针。

sizeof()

-> 计算所需内存空间的大小。

2.单链表的操作实现

1.初始化ListInitiate(SLNode **head)void ListInitiate(SLNode **head) //初始化

{

*head = (SLNode *)malloc(sizeof(SLNode)); //申请头结点,由head指示其地址

(*head)->next = NULL; //置结束标记NULL

}

2.求当前数据元素个数ListLength(SLNode *head)int ListInitiate(SLNode *head)

{

SLNode *p = head; //p指向头结点

int size = 0; //size初始化为0

while(p->next!=NULL) //循环计数

{

p = p->next;

size ++;

}

return size;

}

3.插入ListInsert(SLNode *head, int i, DataType x)int ListInsert(SLNode *head, int i, DataType x)

//在带头结点的单链表head的第i(0<=i<=size)个结点前

//插入一个存放数据元素x的结点。插入成功返回1,失败返回0。

{

SLNode *p, *q;

int j;

p = head;

j = -1;

while(p->next!=NULL && j

//最终让p指向第i-1个结点

{

p = p->next;

j++;

}

if(j!=i-1)

{

printf("插入位置参数错误!n");

return 0;

}

q = (SLNode *)malloc(sizeof(SLNode)); //生成新的结点

q->data = x; //新节点数据域赋值

q->next = p->next; //插入

p->next = q;

return 1;

}

4.删除ListDelete(SLNode head, int t, DataTypex)int ListDelete(SLNode *head, int i, DataType *x)

//删除带头结点单链表head的第i(0<=i<=size-1)个结点

//被删除结点的数据域值由x带回。删除成功返回1,失败返回0。

{

SLNode *p, *s;

int j;

p = head;

j = -1;

while(p->next!=NULL && p->next->next!=NULL && j

//最终p指向第i-1个结点

{

p = p->next;

j++;

}

if(j!=i-1)

{

printf("删除位置参数错误!n");

return 0;

}

s = p->next; //指针s指向第i个结点

*x = s->data; //赋值

p->next = p->next->next; //删除

free(s); //释放内存空间

return 1;

}

5.取数据元素ListGet(SLNode head, int i, DataTypex)int ListGet(SLNode *head, int i, DataType *x)

{

SLNode *p;

int j;

p = head;

j = -1;

while(p->next!=NULL && j

{

p = p->next;

j++;

}

if(j!=i)

{

printf("取元素位置参数错误!n");

return 0;

}

*x = p->data;

return 1;

}

循环单链表

链表的最后一个结点的指针域不再是结束标记,而是指向整个链表的第一个结点,从而使链表形成一个环。(与单链表的实现差别不大,不做讨论。)

双向链表

双向链表也有循环和非循环两种结构,这里讨论带头节点的双向循环链表。

双向循环链表结点的结构体定义如下:typedef struct Node

{

DataType data; //数据域

struct Node *next; //指向后驱结点的指针

struct Node *prior; //指向前驱结点的指针

} DLNode;

双向循环链表的操作实现

1.初始化void ListInitiate(DLNode **head)

{

*head = (DLNode *)malloc(sizeof(DLNode));

(*head)->prior = *head;

(*head)->next = *head;

}

2.插入数据元素int ListTnsert(DLNode *head, int i, DataType x)

//在带头结点的双向循环链表head的第i(0<=i<=size)个结点前

//插入一个存放数据元素x的结点。成功返回1,失败返回0。

{

DLNode *p, *s;

int j;

p = head->next;

j = 0;

while(p->next!=head && j

{

p = p->next;

j++;

}

if(j!=i)

{

printf("插入位置参数出错!");

return 0;

}

s = (DLNode *)malloc(sizeof(DLNode));

s->data = x;

s->prior = p->prior; //插入步骤

p->prior->next = s;

s->next = p;

p->prior = s;

return 1;

}

3.删除数据元素int ListDelete()

//删除带头结点双向循环链表head的第i(0<=i<=size-1)个结点

//被删除的结点的数据元素域值由x带回。成功返回1,失败返回0。

{

DLNode *p;

int j;

p = head->next;

j = 0;

while(p->next!=head && j

{

p = p->next;

j++;

}

if(j!=i)

{

printf("删除位置参数错误!");

return 0;

}

p->prior->next = p->next;

p->next->prior = p->prior;

free(p);

return 1;

}

4.求当前数据元素个数int ListLength(DLNode *head)

{

DLNode *p = head;

int size = 0;

while(p->next != head)

{

p = p->next;

size ++;

}

return size;

}

5.撤销内存空间void Destory(DLNode **head)

{

DLNode *p, *p1;

int i, n = ListLength(*head)

p = *head;

for(i = 0, i<=n, i++)

{

p1 = p;

p = p->next;

free(p1);

}

*head = NULL;

}

你可能感兴趣的:(数据结构c语言版线性表和链表)