数据结构——二十分钟盲打动态链表 (内附排序优化&删除优化版本)

此代码实现了动态链表的????

(1)头插法、尾插法创建

(2)节点的增、删、查

(3)链表求长、逆置、排序(冒泡)和销毁

(4)附加删除和排序的优化版本

详细解释见C代码,已在Qt5上实现:????????????

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

//节点
//数据域:data
//指针域:指向下一个节点,下一个节点的类型是啥呢?就是本尊啊

typedef struct node
{
    int data;
    struct node *next;
}Node;


void traverseList(Node *head) //遍历链表 输出内容
{
    while(head->next)
    {
        printf("%d\n",head->next->data);
        head = head->next;
    }
}

Node * TailCreatList ()  //动态创建链表(尾插法) 在为节点插入新节点
{
    Node *Head= (Node *)malloc(sizeof(Node));
    if(NULL == Head)
        exit(-1);
    Head->next = NULL;

    Node *t;
    t = Head; // 初始化

    int nextdata;
    scanf("%d",&nextdata);

    while(nextdata)
    {
        Node *cur;
        cur = (Node *)malloc(sizeof(Node));
        if(NULL == cur )
            exit(-1);
        cur->data = nextdata;
        t->next = cur;
        t = t->next;
        scanf("%d",&nextdata);
    }
    t->next =NULL;
    return Head;
}

//动态创建链表(头插法)
//头节点后边插入节点,每插入一个当成头节点
//宗旨:先让新来的节点有指向,避免打断原有的指向。

Node * HHeadCreatList()
{
    Node *Head= (Node *)malloc(sizeof(Node));
    if(NULL == Head)
        exit(-1);
    Head->next = NULL;

    int nodedata;
    scanf("%d",&nodedata);
    while(nodedata)
    {
        Node *cur;
        cur = (Node *)malloc(sizeof(Node));
        if(NULL == cur )
            exit(-1);
        cur->data = nodedata;
        cur->next = Head->next;
        Head->next = cur;
        scanf("%d",&nodedata);
    }
    return Head;
}

void traverseListAddress(Node *head) //遍历链表,输出每个的地址
{
    while(head->next)
    {
        printf("%d-->%p\n",head->next->data,head->next->data);
        head = head->next;
    }
}

void  InsertList (Node *Head,int n, int Insertdata) //在数据n后边插入数据Insertdata
{
    Node *p =Head->next;
    while(p)
    {
        if(p->data == n)
        {
            Node *t;
            t = (Node *)malloc(sizeof(Node *));
            t->data = Insertdata;
            t->next = p->next;
            p->next = t;
            break;
        }
        else
            p = p->next;
    }
}
void insertList(Node * head,int insertData) //在头部插入一个数据
{
    Node * cur = (Node *)malloc(sizeof(Node));
    cur->data = insertData;
    cur->next = head->next;
    head->next = cur;
}

int ListLen(Node *Head) //求链表长度
{
    Head = Head->next;
    int len = 0;
    while(Head)
    {
        len++;
        Head = Head->next;
    }
    return len;
}
Node * SearchList(Node * Head,int searchdata) //查找数据,返回指针
{
    Head = Head->next;
    while(Head)
    {
        if(Head->data == searchdata)
            break;
        Head = Head->next;
    }
    return Head;
}

// 删除老版本
void DeleteData1111 (Node * Head,Node *pfind)  //删除某节点 / 先遍历 得到节点的前一个节点
{
    Head = Head->next;
    while(Head->next != pfind)
    {
        Head = Head->next; //找到pfind 的前驱
    }
    Head->next = pfind->next;
    free(pfind);
}

void DeleteData (Node * Head,Node *pfind)   //删除优化。删除非尾节点的时候无需遍历!!!但是此举不适用删除最后一个节点 pfind.next = NULL
{
    if(pfind->next == NULL)
    {
        Head = Head->next;
        while(Head->next != pfind)
        {
            Head = Head->next; //找到pfind 的前驱
        }
        Head->next = pfind->next;
        free(pfind);
    }
    else
    {
        Node *t = pfind->next;          //先给pfind.next 找个替身再 free(t)
        pfind->data = pfind->next->data;     //否则最后free(pfind->next)不就吧删除之后的新序列的节点删了嘛
        pfind->next = pfind->next->next;
        free(t);
    }
}

void reverseList(Node * Head)  //链表逆置
{
    Node *p = Head->next,*q;
    Head->next = NULL;
    while(p != NULL)
    {
        q = p->next;
        p->next = Head->next;
        Head->next = p;
        p = q;
    }
}
void popSortDataList (Node *Head) //链表的换值排序
{
    int N = ListLen(Head);
    Node *p,*q;
    Head = Head->next;
    for(int i=0; i<N-1; i++)
    {
        p = Head;  //每次内重循环都是从头开始
        q = p->next;     //q总是指向p的下一个节点 被比较的节点
        for(int j=0; j<N-1-i; j++)
        {
            if(p->data > q->data)
            {
//                p->data ^= q->data;  //涉及大量的数据搬运  -->  更换指针指向
//                q->data ^= p->data;
//                p->data ^= q->data;

            }
            p = p->next;
            q = q->next;
        }
    }
}

void popSortAddressList (Node *Head)        //链表的换地址排序
{
    /*  换址的注意事项:
     * 1、三指针的定义的位置 放在循环的那个位置? 是放在一层循环里呢还是二层循环里边呢?
     * 2、冒泡排序特别适合在此处,相邻两个数据交换(相邻链表更换指向)
     * 3、(重要!)当更换指向之后的重新链表,,p和q的位序变化了,,需要重新安排次序!!!!!
     * 4、更换指向的时候,注意先后次序。避免换着丢失某个节点
    */
    int N = ListLen(Head);
    Node *prep,*p,*q;
    for(int i=0; i<N-1; i++)
    {
        prep = Head;
        p = prep->next;  //每次内重循环都是从头开始
        q = p->next;     //q总是指向p的下一个节点 被比较的节点
        for(int j=0; j<N-1-i; j++)
        {
            if(p->data > q->data)
            {
                prep->next = q;
                p->next = q->next;
                q->next = p;
                //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                p = prep->next;   //p的前驱次序肯定不会变,但是 p和q 交换之后的指向变成了 prep -> q -> p
                q = p->next;      //所以此步骤意义在于 将更换完次序的 的p、q位序恢复到排序之前
            }
            prep = prep->next;    //三指针同步后移一个
            p = p->next;
            q = q->next;
        }
    }
}

void destroyList(Node * Head)    //销毁链表
{
    Node * p = NULL;
    while(Head) //有多少个 malloc 就有多少个 free
    {
        p = Head->next;
        free(Head);
        Head = p;
    }
}

int main()
{
    Node *Head; //尾插法创建链表
    Head = TailCreatList(); //设一个头结点,creatlist返回头指针!没有输入参数
    traverseList(Head);
    puts("");
    puts("");
    popSortAddressList(Head);
    traverseList(Head);


    //Node *HHead; //头插法创建链表
    //HHead = HHeadCreatList();
    //traverseList(HHead);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值