链表的常见操作

链表的常见操作

链表分为单向链表,双向链表,循环链表,双向循环链表
其中常见操作有:创建,增加,删除,修改,查找,以及单向链表的逆置

链表的定义

链表是一种常见的数据结构链表的存储元素的个数是不受限定的,当要添加更多元素时,存储的个数会随之增加,这种方式就是链表。
链表结点内容分为指针域和数据域,链表就是由这样的一个个结点通过指针域指向连接而成。

单向链表

  • 首先定义一个单向链表
typedef struct a {
    int x;                      //数据域
    struct a * next;            //指针域
}Item;                          //Item为链表的一个结点
typedef Item * linklist;        //linklist为链表

一、链表的创建分为两种:

    一种是头插法创建链表
    另一种是尾插法创建链表

1.头插法创建链表

核心代码

pnew->next = head->next;    //让新结点指向第一个结点
head->next = pnew;    //让头结点指向新结点

完整代码

linklist toucha() {
    linklist head, pnew;    //定义头结点和新结点
    head = (linklist) malloc (sizeof(Item));  //为头结点分配空间
    head->next = NULL;
    int x;    //用x存储临时值
    printf("请输入一个数(输入负数结束输入):");
    scanf("%d", &x);
    while (x>=0) {   //若x为非负数进入循环
        pnew = (linklist) malloc (sizeof(Item));  //为新结点分配空间
        pnew->x = x;    //将临时值赋值给新结点的数据域
        pnew->next = head->next;   //让新结点指向第一个结点
        head->next = pnew;   //让头结点指向新结点
        printf("请输入下一个数(输入负数结束输入):");
        scanf("%d", &x);    //获取下一个值
    }
    return head;     //返回头结点的地址
}

2.尾插法创建链表

核心代码

q->next = NULL;     //q为新结点,让新结点指向空
p->next = q;        //p为上一个结点,让上一个结点指向新结点
p = q;              //让p指向当前结点

完整代码

linklist chuangjian () {
    int x;        //x存储临时值
    printf("请输入一个数(输入负数结束输入):");
    scanf("%d", &x);       //获取临时值
    linklist head, p, q;       //定义头结点head,尾指针p,新结点q
    head = (linklist) malloc (sizeof(Item));      //为头结点分配空间
    head->next = NULL;      //让头结点指向空
    p = head;        //让p指向头结点
    while (x>=0) {       //若临时值非负,则进入循环
        q = (linklist) malloc (sizeof(Item));      //为新结点分配空间
        q->x = x;      //将临时值赋值给新结点的数据域
        q->next = NULL;      //让新结点指向空
        p->next = q;      //让上一个结点指向新结点
        p = q;     //让p指向当前结点
        printf("请输入下一个数(输入负数结束输入):");
        scanf("%d", &x);   //获取临时值
    }
    return head;        //返回头结点的地址
}

二、链表的遍历

void Print(linklist phead) {
    linklist p = phead->next;      //让p指向第一个结点
    while (p) {         //若p不为最后一个结点
        printf("%d\n", p->x);    //打印结点内容
        p = p->next;             //让p指向下一个结点
    }
}

三、链表的增加

void add (linklist phead) {
    linklist p = (linklist) malloc (sizeof(Item));      //创建新结点并为之分配空间
    linklist q = phead;    //q为尾指针
    if (!q) {          //若分配空间失败
        puts("添加失败!");     //输出错误信息
        return;        //退出函数
    }
    else {         //若分配成功
        puts("请输入添加的数:");
        scanf("%d", &p->x);       //获取添加的值
        while(q->next)         //让q指向最后一个结点
            q = q->next;
        q->next = p;     //让q指向新结点
        p->next = NULL;     //让新结点指向空
    }
}

四、链表的删除

void del (linklist phead) {
    int x;    //存储要删除的数字
    linklist p = phead;      //p为前一个结点
    linklist q = phead->next;    //q为要删除的结点
    puts("请输入你要删除的数字:");
    scanf("%d", &x);     //获取要删除的数字
    while (q && q->x != x) {    //若q不为最后一个结点且不是要删除的结点
        p = q;       //让p指向当前结点
        q = q->next;      //让q指向下一个结点
    }
    if (q==NULL)      //若q指向最后一个结点且不为要删除的结点
        puts("未找到该数字!");     //提示未找到该数字
    else {        //若找到要删除的结点
        p->next = q->next;    //让前一个结点指向要删除的下一个结点
        free(q);         //释放q所在的空间
        puts("已删除!");     //输出已删除的信息
   }
}

五、链表的修改

void change(linklist phead) {
    linklist p = phead->next;        //p为要修改的结点
    int x;    //存储临时值
    printf("请输入要修改的数字:");
    scanf("%d", &x);     //获取要修改的数字
    while (p && p->x != x)    //若p不为最后一个结点且不是要修改的结点
        p = p->next;        //让p指向下一个结点
    if (!p)      //若p为最后一个结点且不是要删除的结点
        puts("未找到该数字!");       //提示未找到该数字
    else {     //若找到
        printf("请输入修改之后的数字:");
        scanf("%d", &p->x);       //修改数字
    }
}

六、链表的查找

void find (linklist phead) {
    linklist p = phead->next;     //p为要查找的结点
    int x;     //存储要查找的数字
    printf("请输入要查找的数字:");
    scanf("%d", &x);    //获取要查找的数字
    while (p && p->x != x)  //若p不为最后一个结点且不是要修改的结点
        p = p->next;       //让p指向下一个结点
    if (!p)           //若p为最后一个结点且不是要查找的结点
        puts("未找到该数字!");       //提示未找到该数字
    else        //若找到
        printf("%d\n", p->x);       //打印数字
}

七、链表逆置

void NiZhi (linklist phead) {
    linklist p1, p2;
    p1 = p2 = phead->next;
    phead->next = NULL;
    while (p1) {
        p2 = p1->next;
        p1->next = phead->next;
        phead->next = p1;
        p1 = p2;
    }
}

八、链表排序(冒泡排序)
1.交换数据域

void sort (linklist phead) {
    linklist q = phead->next ;      //让q指向第一个结点
    int flag = 1 ;
    for (int i=0; i<length && flag; i++) {    //lengeh为链表元素个数,若链表无序且未完成排序
        q = phead->next ;       //让q指向第一个结点
        flag = 0 ;         //假定链表有序
        for (; q->next!=NULL; q = q->next)   //q从第一个结点遍历至倒数第二个结点   
            if (q->x>q->next->x) {
                flag = 1 ;
                Item r = q->Student ;
                q->Student = q->next->Student ;
                q->next->Student = r ;
            }
    }
}

2.交换指针域

void sort(linklist phead) {
    int change = 1;    //假定链表无序
    for (int i=0; i<length-1 && change; i++) {   //length为链表元素个数,
        linklist p_pre = phead;    //p_pre指向头结点
        linklist p = p_pre->next;  //p指向第一个结点
        linklist q = p->next;      //q指向第二个结点
        change = 0;    //假定链表有序
        for (; q!=NULL; p = p->next) {   //若q不指向空,则进入循环
            if (p->x>q->x) {     //若前一个值大于后一个值
                change = 1;      //链表无序
                p_pre->next = q;     //使p的前一个结点指向p的后一个结点
                p->next = q->next;    //使p指向q的后一个结点
                q->next = p;       //使q指向p
                //交换p,q
                linklist r = p;    //使r指向p
                p = q;          //使p指向q
                q = r;          //使q指向r
            }
            p_pre = p;      //使p_pre指向当前结点
            q = q->next;    //使q指向q的下一个结点
        }
    }
}

双向循环链表

双向循环链表是单项循环链表的一种拓展(循环链表与双向链表的组合),
循环链表即让最后一个结点不指向空,而是指向头结点,
双向链表的指针域为两个指针,一个指向前驱(前一个结点),一个指向后继(后一个结点)
  • 首先定义一个双向循环链表
typedef struct student {        //定义一个结构体
    int x;
    struct student * llist;     //前驱结点的指针
    struct student * rlist;     //后继结点的指针
} Node, * linklist;             //Node位一个结点, linklist为结点的指针

一、 双向循环链表的创建

linklist chuangjian() {         //尾插法创建链表
    int x;      //存储一个临时值
    printf("请输入一个数字, 键入负数退出!");
    scanf("%d", &x);        //获取临时值
    linklist head, p, q;
    head = (linklist) malloc (sizeof(Node));
    head->llist = NULL;
    head->rlist = NULL;
    p = head;
    while (x>=0) {
        //如果临时值为非负数就创建一个结点
        q = (linklist) malloc (sizeof(Node));
        //将临时值赋值给结点的数据
        q->x = x;
        //使新结点的前驱指针指向原本的前一个结点
        q->llist = p;
        //使新结点的后继指针指向空
        q->rlist = NULL;
        //使前一个结点的后继指针指向新创建的结点
        p->rlist = q;
        //使p指向当前结点
        p = q;
        printf("请输入下一个数字, 键入负数退出!");
        //获取临时值
        scanf("%d", &x);
    }
    q->rlist = head;
    head->llist = q;
    return head;
}

二、双向循环链表的增加

void add (linklist phead) {         //添加结点到链表尾部
    linklist n;
    n = (linklist) malloc (sizeof(Node));   //为要添加的结点动态分配内存
    printf("请输入你要添加的非负数:");
    scanf("%d", &n->x);     //获取添加的结点的数据
    n->rlist = phead;       //使新结点的前驱指向头结点
    n->llist = phead->llist; //使新结点的后继指向第一个结点
    phead->llist->rlist = n;    //使最后一个结点的后继指向新结点
    phead->llist = n;       //使头结点的后继指向新结点
}

三、双向循环链表的删除

void del(linklist phead) {      //删除结点
    int x;
    printf("请输入你要删除的数字:");
    scanf("%d", &x);       //获取要删除的数字
    linklist p, q;
    p = q = phead;      //使p和q都指向头结点
    while (q->rlist != phead && q->x != x) {    //如果q不为最后一个节点且q的值不为要删除的数字
        p = q;          //使p指向当前结点, 即指向前一个结点
        q = q->rlist;   //使q指向下一个结点
    }
    if (q->rlist == phead->rlist)   //若q指向头结点, 则表明未找到该数字
        puts("未找到该数字!");
    else {                          //找到要删除的数字
        p->rlist = q->rlist;        //使前一个结点指向要删除的下一个结点
        q->rlist->llist = p;        //使要删除的下一个结点的前驱指向要删除的前一个结点
        free(q);                    //释放删除的结点空间
    }
}

四、双向循环链表的遍历

void Print(linklist phead, int n) {     //打印链表内容
    linklist p = phead;  //p指向第一个结点
    if (n==1)           //n=1时表示正序输出
        while (p->rlist != phead) {     //若p不为最后一个结点
            p = p->rlist;               //让p指向后一个结点
            printf("%d\n", p->x);       //打印该结点的数据
        }
    else                //否则表示逆序输出
        while (p->llist != phead) {      //若p不为最后一个结点
            p = p->llist;               //让p指向前一个结点
            printf("%d\n", p->x);       //打印该结点的数据
        }
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值