链表的增删改查排序删除等操作自实现

注意事项:

  1. 链表的函数中很容易出现备份当前指针的操作,注意使用时不要马虎
  2. 在使用未typedef的结构体时,前一定要加struct
  3. 其实所谓头插法的遍历就是一种栈 因其为“先进后出”
    采用头插法插入,即在头节点后插入新来的节点
    插入的方法为:让新来的节点有所指向,再打断原指向,即将头节点的next指向新来的节点
#include <stdio.h>


#include<stdlib.h>

//注意事项:
//1.在使用未typedef的结构体时,前一定要加struct
//2.其实所谓头插法的遍历就是一种栈 因其为“先进后出”
typedef struct _Node
{
    int data;

    struct _Node* next;
}Node;

//初始化链表即创建头指针以及头节点
Node* init_list(void)
{
    Node* head = (Node*)malloc(sizeof(Node));
    head->next = NULL;
    return head;
}

//采用头插法插入,即在头节点后插入新来的节点
//插入的方法为:让新来的节点有所指向,再打断原指向,即将头节点的next指向新来的节点
void insert_list(Node* head,int data)
{
    Node* cur = (Node*)malloc(sizeof(Node));
    cur->data = data;
    cur->next = head->next;
    head->next = cur;
}
void traversal_list(Node* head)
{
    Node* phead = head->next;
    while (phead!=NULL)
    {
        printf("%d\n",phead->data);
        phead = phead->next;
    }

}
Node* search_list(Node* head,int data)
{
    int flag = 1;
    Node* phead = head->next;
    while (phead!=NULL)
    {
        if(phead->data!=data)
            phead = phead->next;
        else {
            flag = 0;
            break;
        }
    }
    if(0==flag)
    {
        printf("找到%d\n",data);
        return phead;
    }else {
        printf("未找到%d\n",data);
        return NULL;
    }
}
Node* delete_list(Node* head,Node* p)
{
    //删除节点
    //判断此节点是否在链表中
    int flag = 1;
    Node* phead = head->next;
    while (phead!=NULL)
    {
       if(phead!=p)
           phead = phead->next;
       else
       {
           flag = 0;
           break;
       }
    }
    if(0==flag)
    {
        printf("找到节点\n");

    }else {
        printf("错误:此节点不在本链表中无法删除\n");
        return 0;
    }


    //1. 让它的前一个节点指向它后一个节点
    //2. free这个节点
    Node* p2 = p;
    //先找到它前一个节点
    Node* phead2 = head->next;
    while (phead2->next!=p)
    {
        //注意:传递一级指针改变指针指向,不会改变外边的,因为是仅拷贝了这个地址
        phead2 = phead2->next;
    }
    phead2->next = p2->next;
    free(p2);
}

//排序分两种:
//1.交换数据
//2.交换节点,缺点:实现稍微复杂,但如果节点中除了data还有其他数据,通过data来实现其他内容的排序时显得尤为方便
void sort_list(Node* head)//按pop原理,交换数据
{
    //按节点data的大小从小到大排序
    //原理:设两个相邻的节点
    //      这两个节点就是类比数组冒泡排序中的i,和i+1
    //冒泡的原理即:比较两个相邻数据,一次遍历将最后放到末尾
    //                              二次遍历将次最值放到末尾
    int len = len_list(head);

    //关于冒泡排序的原理:
    //1. 外重循环的i告诉内重循环,j走到哪里停止
    //也就是说:第一次j走到倒数第二个数
    //         第二次j走到倒数第三个数
    //....最后j=0一步不走即结束
    int i =0;
    int j = 0;
    for(i = 0;i<len-1;i++)
    {
        Node* p1 = head->next;
        Node* p2 = p1->next;

        for(j = 0;j<len-1-i;j++)
        {
            if(p1->data>p2->data)
            {
                p1->data ^= p2->data;
                p2->data ^= p1->data;
                p1->data ^= p2->data;
            }
            p1 = p1->next;
            p2 = p1->next;
        }
    }
}

//思想:从头节点将链表一分为2,这步的目的是为了将头节点的next再度置空以便头插法
//      逐个将链表头再以头插法插入链表,即把最后进来的最先再进入链表
void reversal_list(Node* head)
{

    Node* phead = head->next;
    head->next = NULL;
    Node* phead2;
    while (phead!=NULL)
    {
        //备份phead的下一个节点
        phead2 = phead->next;
        //令新来的节点有所指向
        phead->next =head->next;
        //令头节点指向它
        head->next = phead;
        phead =phead2;
    }
}
int  len_list(Node* head)
{
    int len = 0;
    Node* phead = head->next;
    while (phead!=NULL)
    {
        printf("%d\n",phead->data);
        phead = phead->next;
        len++;
    }
    return len;
}
//测试
int main(int argc, char *argv[])
{
    Node* head = init_list();
    insert_list(head,1);
    insert_list(head,2);
    insert_list(head,3);
    insert_list(head,4);
    insert_list(head,666);
    insert_list(head,555);

    traversal_list(head);
    Node* p = search_list(head,2);

    delete_list(head,p);
    traversal_list(head);
    reversal_list(head);
    traversal_list(head);
    int a = len_list(head);
    printf("a = %d\n",a);
    sort_list(head);
    traversal_list(head);
    printf("Hello World!\n");
    return 0;
}

上一篇:单链表实现


下一篇:链表之单链表