数据结构——单向链表

一、链表

1、链表和线性表的关系:链表是线性表的链式存储结构
2、链表给每块数据单独的存储空间,即存储空间地址可不连续。

链表结构
3、结点类型

struct node{
	datatype data;
	struct node *next;
};

二、单向链表

单向链表
1、头结点不存储数据,且为空。
2、引入头结点的原因:在表头插入、表尾插入或者表中间插入都一样,让操作统一、简化。


三、用C语言实现单向链表

1、构造存储结构

typedef int datatype;
typedef struct linklist
{
    datatype data;  /* 数据域 */
    struct linklist *next;  /* 指针域 */
}link_list, *link_plist;

2、初始化

初始化主要的工作:①申请头结点空间;②建立空链表(head->next=NULL

初始化

/* 初始化 */
void init_linklist(link_plist *list)
{
    *list = (link_plist)malloc(sizeof(link_list));
    if(NULL == *list)
    {
        printf("内存申请失败\n");
        perror("malloc");   /* 打印内存申请失败原因 */
        exit(1);
    }
    (*list)->next = NULL;   /* 将next设为NULL,建立空链表 */
}

3、插入

插入主要工作:
第一步:把③的地址放到new->next,即new->next = head->next
第二步:把①的next指向②(new),即head->next = new

链表插入结点

/* 插入 */
void insert_linklist(link_plist head, link_plist new)
{
    new->next = head->next;
    head->next = new;
}

4、删除

删除主要工作:
第一步:将pnode->next连接到dnode->next
第二步:释放dnode

链表删除结点

/* 删除 */
void delete_linklist(link_plist pnode)
{
    link_plist dnode;

    dnode = pnode->next;	/* 没删除之前dnode的地址是pnode->next */
    pnode->next = dnode->next;
    free(dnode);
}

5、判断链表是否为空

判断链表是否为空只需判断head->next是否为NULL即可。

/* 判断是否为空 */
bool isempty(link_plist head)
{
    if(NULL == head->next)
    {
        return true;
    }
    else
    {
        return false;
    } 
}

四、练习题

用单向链表实现数据逆转,首先建立一个包含若干整数的单向链表,然后参考讲义的例子实现数据的逆转。(比如说把1,2,3,4,5逆转成5,4,3,2,1)。

1、逆转思路

①、linklist p, t;p用于指向下一个结点,t用于临时保存结点数据。

②、让p = head->next;,也就是一开始让为头结点的下一个结点,也就是第一个保存数据的结点,这里也就是保持数据1的结点,如下图所示。
逆转思路
③、让head->next = NULL;,也就是让头结点与其它结点断开,如下图所示:

逆转思路
④、用t来保存p结点的数据(t = p;),也就是此时t已经保存了第1个结点的数据,然后让p指向下一个结点p = p->next;p已经来到了第2个结点,接着再将t插入到链表,也就插入第1个结点,因为前面head->next = NULL;,因此插入后如下图所示:
逆转思路
⑤、现在p结点时是指向第二个结点,再让t = p; ,p = p->next;,也就是t已经保存第2个结点的数据了,p已经指向第3个结点了,如下图所示:
逆转思路
⑥、现在让t插入到链表中,根据我们前面讲的链表插入,t是插入到head与第一个结点直接的,如下图所示:

逆转思路
⑦、因此,插入后链表就变成如下图所示:
逆转思路
⑧、按照这个思路下去,最终就能完成逆转了,如下图所示:
逆转思路

⑨、逆转的代码如下:

link_plist p = NULL;
link_plist t = NULL;

p = head->next;
head->next = NULL;
    
while(p != NULL)
{
    t = p;
    p = p->next;
    insert_linklist(head, t);
}

2、创建单向链表

/* 创建单向链表 */
void create_linklist(link_plist head)
{
    link_plist new = NULL;
    link_plist p = head;
    int len = 0;
    int i = 0;

    printf("输入要插入数据的个数:");
    scanf("%d", &len);

    for(i = 0; i < len; i++)
    {
        new = (link_plist)malloc(sizeof(link_list));
        if(NULL == new)
        {
            printf("内存申请失败\n");
            perror("malloc");
            exit(1);
        }
        printf("输入要插入的第%d个数据:", (i+1));
        scanf("%d", &(new->data));
        insert_linklist(p, new);
        p = p->next;

        show_linklist(head);   /* 打印 */
    }
}

3、逆转数据

/* 将数据逆转 */
void sort_linklist(link_plist head)
{
    link_plist p = NULL;
    link_plist t = NULL;

    p = head->next;
    head->next = NULL;
    
    while(p != NULL)
    {
        t = p;
        p = p->next;
        insert_linklist(head, t);	/* 这里实现的是在head后面插入结点,看不明白可看前面插入思路 */
        show_linklist(head);
    }
}

4、主函数main.c

int main(void)
{
    link_plist head;        /* 定义一个头指针 */

    init_linklist(&head);   /* 初始化 */
    create_linklist(head);  /* 创建单向链表 */
    sort_linklist(head);    /* 逆转 */

    return 0;
}

5、测试结果:
测试结果

发布了54 篇原创文章 · 获赞 92 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Sanjay_Wu/article/details/103357336