链表

单向链表定义

对于数组,逻辑关系上相邻的连个元素的物理位置也是相邻的,这种结构的优点是可以随机存储任意位置的元素,但缺点是如果从数组中间删除或插入元素时候,需要大量移动元素,效率不高。

数组的优缺点

链式存储结构的特点,元素的存储单元可以是连续的,也可以是不连续的,因此为了表示每个元素a,与其接后的元素a+1之间的关系,对于元素a,除了存储其本身信息外,还需要存储一个指示其接后元素的位置。这两部分数据成为结点(node)。

一个结点中存储的数据元素被成为数据域。存储接后存储位置的域叫做指针域。n个结点(ai(1<=i<=n)的存储映像链接成一个链表。

整个链表必须从头结点开始进行,头结点的指针指向下一个结点的位置,最后一个结点的指针指向NULL。

在链表中,通过指向接后结点位置的指针实现将链表中每个结点“链”到一起。链表中第一个结点称之为头结点。

这里写图片描述

这里写图片描述

这里写图片描述

单向链表数据结构定义

struct list
{
    int data;//链表数据域
    struct list *next;//链表指针域
};

单向链表的实现

struct list *create_list()//建立一个节点
void traverse(struct list *ls)//循环遍历链表
struct list *insert_list(struct list *ls, int n, int data)//在指定位置插入元素
int delete_list(struct list *ls, int n)//删除指定位置元素
int count_list(struct list *ls)//返回链表元素个数
void clear_list(struct list *ls)//清空链表,只保留首节点
int empty_list(struct list *ls)//返回链表是否为空
struct list *locale_list(struct list *ls, int n)//返回链表指定位置的节点
struct list *elem_locale(struct list *ls, int data)//返回数据域等于data的节点
int elem_pos(struct list *ls, int data)//返回数据域等于data的节点位置
struct list *last_list(struct list *ls)//得到链表最后一个节点
void merge_list(struct list *st1, struct list *ls2)//合并两个链表,结果放入st1中
void reverse(struct list *ls)//链表逆置

这里写图片描述

这里写图片描述

删除元素操作

这里写图片描述

这里写图片描述

这里写图片描述

逆置链表-方式1,移动指针域

这里写图片描述

逆置链表-方式2,移动数据域

这里写图片描述

逆置操作
1.判断首节点的next是否为NULL;
2.判断首节点next的next是否为空,如果为空证明链表除首节点之外只有一个节点,所以不需要逆置;
3.定义一个指针last,指向首节点的next域,因为逆置之后,该域为链表尾节点;
4.定义三个指针,分别代表前一个节点,当前节点,下一个节点;
5.前节点指向链表首节点;
6.当前节点指向链表首节点的next域;
7.下一个节点为NULL;
8.循环条件判断当前节点是否为NULL,如果为NULL退出循环;
a)下一个节点指向当前节点的下一个节点;
b)当前节点的下一个节点指向前一个节点;
c)前一个节点指向当前节点;
d)当前节点指向下一个节点;
9.循环完成;
10.设置last节点的next为NULL;
11.设置链表首节点的next为前一个节点。

代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

struct list {
    int data;
    struct list *next;
};

/**
 * 创建节点.
 * @return
 */
struct list *create_list() {
    struct list *p = malloc(sizeof(struct list));
    memset(p, 0, sizeof(p));
    return p;
}

/**
 * 指定位置插入节点.
 * @param ls
 * @param n
 * @param data
 * @return
 */
struct list *insert_list(struct list *ls, int n, int data) {
    struct list *p = ls;
    while (p && n--) {
        p = p->next;
    }

    if (p == NULL)
        return NULL;

    struct list *node = create_list();
    memset(node, 0, sizeof(node));
    node->data = data;
    node->next = p->next;
    p->next = node;

    return node;
}

/**
 * 删除指定节点
 * @param ls
 * @param n
 * @return
 */
int delete_list(struct list *ls, int n) {
    struct list *p = ls;
    while (p && n--) {
        p = p->next;
    }

    struct list *q = p->next;
    int data = q->data;
    p->next = q->next;
    free(q);
    return data;
}

/**
 * 计算列表长度.
 * @param ls
 * @return
 */
int count_list(struct list *ls) {
    // 不能算首节点.
    struct list *p = ls->next;
    int count = 0;
    while (p) {
        p = p->next;
        count++;
    }

    return count;
}

void clear_list(struct list *ls) {
    // 清空节点,但是不能释放头节点.
    struct list *p = ls->next;
    while (p) {
        struct list *q = p->next;
        free(p);
        p = q;
    }
    // 重点,这里必须把首节点的next置空.
    ls->next = NULL;
}

/**
 * 寻找最后一个节点
 * @param ls
 * @return
 */
struct list *last_list(struct list *ls) {
    struct list *p = ls;
    struct list *last = NULL;
    while (p) {
        last = p;
        p = p->next;
    }

    return last;
}

/**
 * 合并列表
 * @param st1
 * @param ls2
 */
void merge_list(struct list *st1, struct list *ls2) {
    struct list *last = last_list(st1);
    last->next = ls2->next;
    free(ls2);
}

/**
 * 列表翻转.
 * @param ls
 */
void reverse(struct list *ls) {
    struct list *pre = ls;
    struct list *cur = ls->next;
    struct list *next = NULL;
    struct list *last = ls->next;
    while (cur) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    last->next = NULL;
    ls->next = pre;
}

// 链表的冒泡排序
void bubble_sort(struct list *ls) {
    int count = count_list(ls);
    int i,j;
    for (i = 0;  i< count; i++) {
        struct list *p = ls->next;
        for (j = 0; j < count - i - 1; j++) {
            struct list *q = p->next;
            if (p->data > q->data) {
                int temp = q->data;
                q->data = p->data;
                p->data = temp;
            }
            p = q;
        }
    }
}

/**
 * 遍历列表
 * @param ls
 */
void traverse(struct list *ls) {
    struct list *p = ls->next;
    while (p) {
        printf("data = %d\n", p->data);
        p = p->next;
    }
}

int main() {
    int i;
    struct list *first = create_list();
    struct list *second = create_list();
    for (i = 0; i < 10; i++) {
        struct list *node = create_list();
        insert_list(first, i, i);
    }
    for (i = 100; i < 110; i++) {
        struct list *node = create_list();
        insert_list(second, 0, i);
    }
    //clear_list(first);
    printf("count = %d\n", count_list(first));
    delete_list(first, 3);
    //traverse(first);
    printf("data = %d\n", last_list(first)->data);
    printf("Hello, World!\n");
    merge_list(first, second);
    //traverse(first);
    printf("-----------------\n");
    reverse(first);
    traverse(first);
    printf("-----------------\n");
    printf("-----------------\n");
    bubble_sort(first);
    traverse(first);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值