数据结构——单向链表

开始学习数据结构,虽然部分之前C都学过,还是总结一下。内容比较多

直接看例子

list.h  //头文件

#include<stdlib.h>
#include<stdio.h>
typedef struct _Node       //节点定义
{
        int data;                   //数据域
        struct Node * next;  //指针域
}Node;

Node * creatList();  //建立链表

void insertList(Node* head,int data);  //插入

void traverseList(Node * head);          //遍历

int  lenList(Node * head);                    //求表长

Node* searchList(Node* head,int find);//查找

void  deleteList(Node * head, Node * pfind);  //删除

void popSortList(Node* head);                          //排序

void reverseList(Node* head);                            //反转

void destoryList(Node * head);                            //销毁

 

list.c   //实现,重点!

#include"list.h"   //自包含
//带有头节点的链表
//首先说明:head指针 指向一个 头节点 ,头节点是存放了首节点的地址。首节点才是我们需要的链表开始。

//所以我们需要的链表一开始的地址是 head->next;

//以下入参性检查省略
Node * creatList()  //建立空链表
{
    Node* head=(Node*)malloc(sizeof(Node));
    head->next=NULL;
    return head;
}

void insertList(Node* head,int data)  //插入(头插法)
{
    Node* cur=(Node*)malloc(sizeof(Node));
    cur->data=data;
    cur->next=head->next;  //让先来的节点先有所可依
    head->next=cur;            //再打断原来的关系
}

void traverseList(Node * head)          //遍历
{
    head=head->next;
    while(head)
    {
        printf("%2d\t",head->data);
        head=head->next;
    }
    printf("\n");
}

int  lenList(Node * head)                    //求表长
{
    int count=0;
    head=head->next;
    while(head)
    {
        count++;
        head=head->next;
    }
    return count;
}

Node* searchList(Node* head,int find)//查找
{
    head=head->next;
    while(head)
    {
        if(head->data ==  find)
            break ;
        else
            head=head->next;
    }
    return head;     //这里把 if 和 else 两个return head和NULL合并了,没有找到自然为空
}

void  deleteList(Node * head, Node * pfind)  //删除某个节点
{
    if(pfind->next == NULL) //方法一
    {
        while(head->next != pfind)                //方法一,实际上还是完成了一次遍历
            head=head->next;
        head->next=pfind->next;
        free(pfind);
    }
    else    //方法二
    {
        Node * t = pfind->next;  //要删除节点的下一个节点
        pfind->data = t->data;    //让要删除的节点的下一个节点的值 赋给要删除的节点
        //这样就是需要删除 t,这个方法就是需要pfind->next 不为空即可
        pfind->next=t->next;
        free(t);
    }
}

void popSortList(Node* head)                          //排序
{
#if 0
    int len=lenList(head);
    for(int i=0 ; i< len-1 ; i++)   //冒泡法,由于这里冒泡是相邻之间比较,所以只需要到倒数第二个数就可以
    {                                         //这样就是最后两个数相比
        Node*p=head->next;     //每次都要从头开始
        Node*q=p->next;
        for(int j=0;j<len-1-i;j++)  //比的次数,就是从看比较换位后,剩多少需要交换,所以减 i
        {
            if(p->data>q->data)
            {
                p->data ^=q->data;  //无参交换
                q->data ^=p->data;
                p->data ^=q->data;
            }
            p=p->next;
            q=p->next;
        }
    }
#endif
    //不交换值,改变链表的链接顺序,本质也是进行排序,可看下图,可能第一次较复杂,结合图一起看就好多了


   

 Node *p,*q,*pre;
    int len=lenList(head);
    for(int i=0 ; i< len-1 ; i++)
    {
        pre=head;             //head可能还要用,所以不改变head,用一个替身
        p=head->next;
        q=p->next;
        for(int j=0;j<len-1-i;j++)
        {
            if(p->data>q->data)
            {
                pre->next=q;   //这里主要是看图中,把链表进行变直
                p->next=q->next;  //再这里先进行第一步,第二步不能先打断 q->next=p;
                q->next=p;    //q->next一打断,q 原来的 next 则没有连接找不到,则内存泄露

                pre=q;       //在这里的结果实际上p q的顺序变成q p了,这样逻辑与之前不同,需要再交换回来
                q=p->next;  //这里直接把 pre移到 q的位置上,q变成下一位,直接进行移到下一位,用continue跳过后面的移位
                continue;
            }
            pre=pre->next;
            p=p->next;
            q=p->next;
        }
    }
}

void reverseList(Node* head)     //反转,本质也是头插法,链表头插到另一个链表
{
    Node * h=head->next;
    head->next=NULL;   //打散头节点,让它变成空链表,上面行的 h 也就是接手后面的节点
    Node*t;
    while(h)
    {
        t=h->next;          //跟下面的销毁释放一样,若不为空,找一个替身,先指向下一个
        h->next=head->next; //头插法
        head->next=h;
        h=t;                //指向的下一个继续进行上面的操作,继续头插,插入就在上面节点的前面了
    }
}

void destoryList(Node * head)                            //销毁释放
{
    Node *t;
    while(head)
    {
        t=head->next;       //若不为空,找一个替身,先指向下一个
        free(head);          //再销毁本身,否则无法一个接一个销毁
        head=t;
    }
}

 

main函数

#include <stdio.h>
#include"list.h"
#include<time.h>
#include<stdlib.h>
int main()
{
    Node * head=creatList();
    traverseList(head);
    srand(time(NULL));  //产生随机数
    for(int i=0;i<10;i++)
    {
         insertList(head,rand()%10);
    }
    traverseList(head);
    int len =lenList(head);
    printf("len=%d\n",len);

#if 0
    Node* pfind=searchList(head,8);
    if(pfind!=NULL)
    {
          printf("find in the list\n");
//        deleteList(head,pfind);           //只能删除一个8

        do
        {
            deleteList(head,pfind);        //利用do while 能删除所有 8
        }
        while(pfind=searchList(head,8));
        traverseList(head);
    }
#endif

    popSortList(head);
    traverseList(head);

    reverseList(head);
    traverseList(head);

    destoryList(head);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值