链表的学习

1 链表概述

所谓的链表,指的是线性表的链式存储结构,数据存储的时候可以存储当前数据记录,同时存储下一条数据记录的存储空间的地址,在访问的时候,可以通过地址访问到下一条数据记录。

链表的分类

1.

  1. 按照链表结点数据的访问方向:

a.

  1. 单向链表:结点在存储数据的时候,同时存储下一个结点存储空间的地址,只能从当前结点访问到下一个结点,不能从下一个结点访问到当前结点,整个访问过程是单向的。

b.

  1. 双向链表:结点在存储数据的时候,同时存储后继结点存储空间地址和前驱结点存储空间地址,可以从当前访问到后继结点,后继结点也可以访问到当前结点。整个访问是双向的。

2.

  1. 按照是否存在头结点:

数据域:指的是数据记录的存储空间。

头结点:作为整个链表的起始结点,

1) 如果数据域为有效数据域,可以参与数据的操作,起始结点会随着数据操作而改变。此时称为数据结点而非头结点;

2) 如果数据域为无效数据域,不参与数据的运算,此时链表中的起始结点不会改变。称为链表的头结点。

a.

  1. 带头结点链表

起始结点数据域为无效数据;

b.

  1. 不带头结点链表

起始结点数据域为有效数据域。

3.

  1. 按照链表是否带环

a.

  1. 环形链表:

b.

  1. 非环形链表

1.带头结点链表初始化

/* 结点数据域类型:可以根据实际应用需要存储的数据记录进行抽象 */
#if 0
typedef struct Stu {
    int num;
    char name[32];
    int score;
} data_t;
#else 
typedef int data_t;
#endif
 
/* 整个结点数据类型: */
typedef struct node {
    data_t data;		/* 当前结点数据域:存储当前结点的数据 */
    struct node *next;	        /* 当前结点指针域:存储下一个结点空间的起始地址 */
} node_t;


node_t *CreateLinkList(void)
{
    node_t *head;
 
    /* 开辟头结点存储空间 */
    head = malloc(sizeof(node_t));
    if (head == NULL)
        return head;
 
    memset(head, 0, sizeof(node_t));
    head->next = NULL; /* 设置头结点指针域为NULL,表示没有后继结点 */
 
    return head;
}

2.链表插入数据元素

int InsertLinkList(node_t *head, int local, data_t mydata)
{
    int i;
    node_t *p = head;
    node_t *q;
 
    /* 判断插入位置是否满足条件:local >= 0 */
    if (local < 0)
        return -1;
 
    /* 找到需要插入结点的前一个结点 */
    for (i = 0; i < local && p != NULL; i++) {
	p = p->next;
    }
    if (p == NULL)
        return -1;
 
    /* 创建需要插入数据结点空间 */
    q = malloc(sizeof(node_t));
    if (q == NULL)
        return -1;
    memset(q, 0, sizeof(node_t));
    q->data = mydata;
 
    /* 插入结点 */
    q->next = p->next;
    p->next = q;
 
    return 0;
}

3.遍历链表

void DisplayLinkList(node_t *head)
{
    node_t *p = head->next;
 
    while(p != NULL) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

4.删除链表中的元素

 

int DeleteLinkList(node_t *head, int local)
{
    int i;
    node_t *p = head;
    node_t *q;
 
    /* 判断链表是否为空表:空表删除失败 */
    if (head->next == NULL)
        return -1;
 
    /* 找要删除结点的前一个结点 */
    for (i = 0; i < local && p->next != NULL; i++) 
        p = p->next;
    if (p->next == NULL)
        return -1;
 
    /* 删除结点 */
    q = p->next;
    p->next = q->next;
    free(q);
 
    return 0;
}

5.链表查询元素

int SelectLinkList(node_t *head, int local, data_t *mydata)
{
    int i;
    node_t *p;
 
    /* 判断链表是否为空表 */
    if (head->next == NULL)
        return -1;
		
    /* 查找到指定序号的结点 */ 
    p = head->next;
    for (i = 0; i < local && p != NULL; i++)
        p = p->next;
    if (p == NULL)
        return -1;
    /* 返回结点的数据信息 */
    *mydata = p->data;
 
    return 0;
}

6.链表修改元素

int UpdateLinkList(node_t *head, int local, data_t newdata)
{
    int i;
    node_t *p;
 
    /* 判断链表是否为空表 */
    if (head->next == NULL)
        return -1;
		
    /* 查找到指定序号的结点 */ 
    p = head->next;
    for (i = 0; i < local && p != NULL; i++)
        p = p->next;
    if (p == NULL)
        return -1;
    /* 返回结点的数据信息 */
    p->data = newdata;
 
    return 0;
}

7.其他运算

/* 判断链表是否为空表 */
int isEmptyLinkList(node_t *head)
{
    return (head->next == NULL);
}
 
/* 判断链表是否为满表 */
int isFullLinkList(node_t *head)
{
    return 0;		/* 链表不可能为满表,返回0表示false */
}
 
/* 计算链表中有效数据结点个数,链表的长度 */
int LengthLinkList(node_t *head)
{
    int len = 0;
    node_t *p = head->next;
 
    while(p != NULL) {
        len++;
        p = p->next;
    }
    return len;
}
 
/* 清空链表的数据结点,头结点保留 */
void ClearLinkList(node_t *head)
{
    node_t *q;
    node_t *p = head->next;
    head->next = NULL;
 
    while(p != NULL) {
        q = p;
        p = p->next;
        free(q);
    }
}
 
/* 销毁整个链表 */
void DestoryLinkList(node_t **head)
{
    node_t *q;
    node_t *p = *head;
    *head = NULL;
 
    while(p != NULL){
        q = p;
        p = p->next;
        free(q);
    }
}

8.链表的排序

 

void SortLinkList(node_t *head)
{
    node_t *p;
    node_t *q;
    node_t *r;
    /* 判断链表是否为空表:空表直接结束 */
    if (head->next == NULL)
        return;
 
    p = head->next->next;		/* 第0个有效数据结点作为有效序列,从第1个有效数据结点开始做顺序插入排序 */
    head->next->next = NULL;
    /* 从第1个结点开始循环遍历,并做顺序插入 */ 
    while(p != NULL) {
        q = p;			/* 遍历需要排序的结点p赋值给运算结点q */
	p = p->next; /* 遍历到下一个结点 */
 
        /* 循环找到需要插入结点位置的前一个结点 */
        r = head;
        while(r->next != NULL) {		/* r的下一个结点是否存在,r->next == NULL说明r为有效链表的最后一个结点 */
            if (r->next->data > q->data) /* 下一个结点数据 > 大于插入结点的数据,说明当前结点为插入结点大的前一个结点 */
                break;
            r = r->next; 
        }
        /* 在r结点后插入待排序结点q */
        q->next = r->next;
        r->next = q;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值