• 链表的基本操作


    Example 1

    ////////////////////////////////////////////    
    //单链表的初始化,建立,插入,查找,删除。//    
    ////////////////////////////////////////////     
    #include <stdio.h>    
    #include <stdlib.h>    
    typedef int ElemType;    
    ////////////////////////////////////////////     
    //定义结点类型     
    typedef struct Node    
    {    
        ElemType data;              //单链表中的数据域     
        struct Node *next;          //单链表的指针域     
    }Node,*LinkedList;    
    ////////////////////////////////////////////     
    //单链表的初始化    
    LinkedList LinkedListInit()    
    {    
        Node *L;    
        L = (Node *)malloc(sizeof(Node));   //申请结点空间     
        if(L == NULL)                       //判断是否有足够的内存空间     
            printf("申请内存空间失败/n");    
        L->next = NULL;                  //将next设置为NULL,初始长度为0的单链表     
    }    
    ////////////////////////////////////////////     
    //单链表的建立1,头插法建立单链表    
    LinkedList LinkedListCreatH()    
    {    
        Node *L;    
        L = (Node *)malloc(sizeof(Node));   //申请头结点空间    
        L->next = NULL;                      //初始化一个空链表    
            
        ElemType x;                         //x为链表数据域中的数据    
        while(scanf("%d",&x) != EOF)    
        {    
            Node *p;    
            p = (Node *)malloc(sizeof(Node));   //申请新的结点     
            p->data = x;                     //结点数据域赋值     
            p->next = L->next;                    //将结点插入到表头L-->|2|-->|1|-->NULL     
            L->next = p;     
        }    
        return L;     
    }     
    ////////////////////////////////////////////     
    //单链表的建立2,尾插法建立单链表    
    LinkedList LinkedListCreatT()    
    {    
        Node *L;    
        L = (Node *)malloc(sizeof(Node));   //申请头结点空间    
        L->next = NULL;                  //初始化一个空链表    
        Node *r;    
        r = L;                          //r始终指向终端结点,开始时指向头结点     
        ElemType x;                         //x为链表数据域中的数据    
        while(scanf("%d",&x) != EOF)    
        {    
            Node *p;    
            p = (Node *)malloc(sizeof(Node));   //申请新的结点     
            p->data = x;                     //结点数据域赋值     
            r->next = p;                 //将结点插入到表头L-->|1|-->|2|-->NULL     
            r = p;     
        }    
        r->next = NULL;     
            
        return L;       
    }    
    ////////////////////////////////////////////     
    //单链表的插入,在链表的第i个位置插入x的元素    
    LinkedList LinkedListInsert(LinkedList L,int i,ElemType x)    
    {    
        Node *pre;                      //pre为前驱结点     
        pre = L;    
        int tempi = 0;    
        for (tempi = 1; tempi < i; tempi++)    
            pre = pre->next;                 //查找第i个位置的前驱结点     
        Node *p;                                //插入的结点为p    
        p = (Node *)malloc(sizeof(Node));    
        p->data = x;     
        p->next = pre->next;    
        pre->next = p;    
            
        return L;                               
    }     
    ////////////////////////////////////////////     
    //单链表的删除,在链表中删除值为x的元素    
    LinkedList LinkedListDelete(LinkedList L,ElemType x)    
    {    
        Node *p,*pre;                   //pre为前驱结点,p为查找的结点。     
        p = L->next;    
        while(p->data != x)              //查找值为x的元素     
        {       
            pre = p;     
            p = p->next;    
        }    
        pre->next = p->next;          //删除操作,将其前驱next指向其后继。     
        free(p);    
        return L;    
    }     
    /////////////////////////////////////////////    
    int main()    
    {    
        LinkedList list,start;    
    /*  printf("请输入单链表的数据:");   
        list = LinkedListCreatH();  
        for(start = list->next; start != NULL; start = start->next)  
            printf("%d ",start->data);  
        printf("/n");  
    */  printf("请输入单链表的数据:");     
        list = LinkedListCreatT();    
        for(start = list->next; start != NULL; start = start->next)    
            printf("%d ",start->data);    
        printf("/n");    
        int i;    
        ElemType x;    
        printf("请输入插入数据的位置:");    
        scanf("%d",&i);    
        printf("请输入插入数据的值:");    
        scanf("%d",&x);    
        LinkedListInsert(list,i,x);    
        for(start = list->next; start != NULL; start = start->next)    
            printf("%d ",start->data);    
        printf("/n");    
        printf("请输入要删除的元素的值:");    
        scanf("%d",&x);    
        LinkedListDelete(list,x);     
        for(start = list->next; start != NULL; start = start->next)    
            printf("%d ",start->data);    
        printf("/n");    
            
        return 0;    
    }     
       
    

    Example 2

    #define NULL 0
    #define TYPE struct stu
    #define LEN sizeof(struct stu)
    
    struct stu{
    	int num;
    	int age;
    	struct stu *next;
    }
    
    TYPE *create(int n){
    	struct stu *phead, *pf, *pb;
    	int i;
    	for(i=0; i<n; i++){
    		pb = (TYPE *)malloc(LEN);
    		printf("input number and age
    ");
    		scanf("%d%d",&pb->num,&pb->age);
    		if (i == 0){
    			pf=head=pb;
    		}else{
    			pf->next=pb;
    		}
    
    		pb->next=NULL;
    		pf=pb;
    
    		return(head);
    
    	}
    }
    

    Example3

    最近在复习数据结构,想把数据结构里面涉及的都自己实现一下,完全是用C语言实现的。
    自己编写的不是很好,大家可以参考,有错误希望帮忙指正,现在正处于编写阶段,一共将要实现19个功能。到目前我只写了一半,先传上来,大家有兴趣的可以帮忙指正,谢谢
    在vs2010上面编译运行无错误。
    每天都会把我写的新代码添加到这个里面。直到此链表完成。
    #include "stdafx.h"
    #include "stdio.h"
    #include <stdlib.h>
    #include "string.h"
     
    typedef int elemType ;
     
    /************************************************************************/
    /*             以下是关于线性表链接存储(单链表)操作的18种算法        */
     
    /* 1.初始化线性表,即置单链表的表头指针为空 */
    /* 2.创建线性表,此函数输入负数终止读取数据*/
    /* 3.打印链表,链表的遍历*/
    /* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为一个空表 */
    /* 5.返回单链表的长度 */
    /* 6.检查单链表是否为空,若为空则返回1,否则返回0 */
    /* 7.返回单链表中第pos个结点中的元素,若pos超出范围,则停止程序运行 */
    /* 8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL */
    /* 9.把单链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0 */
    /* 10.向单链表的表头插入一个元素 */
    /* 11.向单链表的末尾添加一个元素 */
    /* 12.向单链表中第pos个结点位置插入元素为x的结点,若插入成功返回1,否则返回0 */
    /* 13.向有序单链表中插入元素x结点,使得插入后仍然有序 */
    /* 14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停止程序运行 */
    /* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停止程序运行 */
    /* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停止程序运行 */
    /* 17.从单链表中删除值为x的第一个结点,若删除成功则返回1,否则返回0 */
    /* 18.交换2个元素的位置 */
    /* 19.将线性表进行快速排序 */
     
     
    /************************************************************************/
    typedef struct Node{    /* 定义单链表结点类型 */
        elemType element;
        Node *next;
    }Node;
     
     
    /* 1.初始化线性表,即置单链表的表头指针为空 */
    void initList(Node **pNode)
    {
        *pNode = NULL;
        printf("initList函数执行,初始化成功
    ");
    }
     
    /* 2.创建线性表,此函数输入负数终止读取数据*/
    Node *creatList(Node *pHead)
    {
        Node *p1;
        Node *p2;
     
        p1=p2=(Node *)malloc(sizeof(Node)); //申请新节点
        if(p1 == NULL || p2 ==NULL)
        {
            printf("内存分配失败
    ");
            exit(0);
        }
        memset(p1,0,sizeof(Node));
     
        scanf("%d",&p1->element);    //输入新节点
        p1->next = NULL;         //新节点的指针置为空
        while(p1->element > 0)        //输入的值大于0则继续,直到输入的值为负
        {
            if(pHead == NULL)       //空表,接入表头
            {
                pHead = p1;
            }
            else               
            {
                p2->next = p1;       //非空表,接入表尾
            }
            p2 = p1;
            p1=(Node *)malloc(sizeof(Node));    //再重申请一个节点
            if(p1 == NULL || p2 ==NULL)
            {
            printf("内存分配失败
    ");
            exit(0);
            }
            memset(p1,0,sizeof(Node));
            scanf("%d",&p1->element);
            p1->next = NULL;
        }
        printf("creatList函数执行,链表创建成功
    ");
        return pHead;           //返回链表的头指针
    }
     
    /* 3.打印链表,链表的遍历*/
    void printList(Node *pHead)
    {
        if(NULL == pHead)   //链表为空
        {
            printf("PrintList函数执行,链表为空
    ");
        }
        else
        {
            while(NULL != pHead)
            {
                printf("%d ",pHead->element);
                pHead = pHead->next;
            }
            printf("
    ");
        }
    }
     
    /* 4.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为一个空表 */
    void clearList(Node *pHead)
    {
        Node *pNext;            //定义一个与pHead相邻节点
     
        if(pHead == NULL)
        {
            printf("clearList函数执行,链表为空
    ");
            return;
        }
        while(pHead->next != NULL)
        {
            pNext = pHead->next;//保存下一结点的指针
            free(pHead);
            pHead = pNext;      //表头下移
        }
        printf("clearList函数执行,链表已经清除
    ");
    }
     
    /* 5.返回单链表的长度 */
    int sizeList(Node *pHead)
    {
        int size = 0;
     
        while(pHead != NULL)
        {
            size++;         //遍历链表size大小比链表的实际长度小1
            pHead = pHead->next;
        }
        printf("sizeList函数执行,链表长度 %d 
    ",size);
        return size;    //链表的实际长度
    }
     
    /* 6.检查单链表是否为空,若为空则返回1,否则返回0 */
    int isEmptyList(Node *pHead)
    {
        if(pHead == NULL)
        {
            printf("isEmptyList函数执行,链表为空
    ");
            return 1;
        }
        printf("isEmptyList函数执行,链表非空
    ");
     
        return 0;
    }
     
    /* 7.返回单链表中第pos个结点中的元素,若pos超出范围,则停止程序运行 */
    elemType getElement(Node *pHead, int pos)
    {
        int i=0;
     
        if(pos < 1)
        {
            printf("getElement函数执行,pos值非法
    ");
            return 0;
        }
        if(pHead == NULL)
        {
            printf("getElement函数执行,链表为空
    ");
            return 0;
            //exit(1);
        }
        while(pHead !=NULL)
        {
            ++i;
            if(i == pos)
            {
                break;
            }
            pHead = pHead->next; //移到下一结点
        }
        if(i < pos)                  //链表长度不足则退出
        {
            printf("getElement函数执行,pos值超出链表长度
    ");
            return 0;
        }
     
        return pHead->element;
    }
     
    /* 8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL */
    elemType *getElemAddr(Node *pHead, elemType x)
    {
        if(NULL == pHead)
        {
            printf("getElemAddr函数执行,链表为空
    ");
            return NULL;
        }
        if(x < 0)
        {
            printf("getElemAddr函数执行,给定值X不合法
    ");
            return NULL;
        }
        while((pHead->element != x) && (NULL != pHead->next)) //判断是否到链表末尾,以及是否存在所要找的元素
        {
            pHead = pHead->next;
        }
        if((pHead->element != x) && (pHead != NULL))
        {
            printf("getElemAddr函数执行,在链表中未找到x值
    ");
            return NULL;
        }
        if(pHead->element == x)
        {
            printf("getElemAddr函数执行,元素 %d 的地址为 0x%x
    ",x,&(pHead->element));
        }
     
        return &(pHead->element);//返回元素的地址
    }
     
    /* 9.把单链表中第pos个结点的值修改为x的值,若修改成功返回1,否则返回0 */
    int modifyElem(Node *pNode,int pos,elemType x)
    {
        Node *pHead;
        pHead = pNode;
        int i = 0;
     
        if(NULL == pHead)
        {
            printf("modifyElem函数执行,链表为空
    ");
        }
        if(pos < 1)
        {
            printf("modifyElem函数执行,pos值非法
    ");
            return 0;
        }
        while(pHead !=NULL)
        {
            ++i;
            if(i == pos)
            {
                break;
            }
            pHead = pHead->next; //移到下一结点
        }
        if(i < pos)                  //链表长度不足则退出
        {
            printf("modifyElem函数执行,pos值超出链表长度
    ");
            return 0;
        }
        pNode = pHead;
        pNode->element = x;
        printf("modifyElem函数执行
    ");
         
        return 1;
    }
     
    /* 10.向单链表的表头插入一个元素 */
    int insertHeadList(Node **pNode,elemType insertElem)
    {
        Node *pInsert;
        pInsert = (Node *)malloc(sizeof(Node));
        memset(pInsert,0,sizeof(Node));
        pInsert->element = insertElem;
        pInsert->next = *pNode;
        *pNode = pInsert;
        printf("insertHeadList函数执行,向表头插入元素成功
    ");
     
        return 1;
    }
     
    /* 11.向单链表的末尾添加一个元素 */
    int insertLastList(Node **pNode,elemType insertElem)
    {
        Node *pInsert;
        Node *pHead;
        Node *pTmp; //定义一个临时链表用来存放第一个节点
     
        pHead = *pNode;
        pTmp = pHead;
        pInsert = (Node *)malloc(sizeof(Node)); //申请一个新节点
        memset(pInsert,0,sizeof(Node));
        pInsert->element = insertElem;
     
        while(pHead->next != NULL)
        {
            pHead = pHead->next;
        }
        pHead->next = pInsert;   //将链表末尾节点的下一结点指向新添加的节点
        *pNode = pTmp;
        printf("insertLastList函数执行,向表尾插入元素成功
    ");
     
        return 1;
    }
     
    /* 12.向单链表中第pos个结点位置插入元素为x的结点,若插入成功返回1,否则返回0 */
     
     
    /* 13.向有序单链表中插入元素x结点,使得插入后仍然有序 */
    /* 14.从单链表中删除表头结点,并把该结点的值返回,若删除失败则停止程序运行 */
    /* 15.从单链表中删除表尾结点并返回它的值,若删除失败则停止程序运行 */
    /* 16.从单链表中删除第pos个结点并返回它的值,若删除失败则停止程序运行 */
    /* 17.从单链表中删除值为x的第一个结点,若删除成功则返回1,否则返回0 */
    /* 18.交换2个元素的位置 */
    /* 19.将线性表进行快速排序 */
     
    /******************************************************************/
    int main()
    {
        Node *pList=NULL;
        int length = 0;
     
        elemType posElem;
     
        initList(&pList);       //链表初始化
        printList(pList);       //遍历链表,打印链表
     
        pList=creatList(pList); //创建链表
        printList(pList);
         
        sizeList(pList);        //链表的长度
        printList(pList);
     
        isEmptyList(pList);     //判断链表是否为空链表
         
        posElem = getElement(pList,3);  //获取第三个元素,如果元素不足3个,则返回0
        printf("getElement函数执行,位置 3 中的元素为 %d
    ",posElem);   
        printList(pList);
     
        getElemAddr(pList,5);   //获得元素5的地址
     
        modifyElem(pList,4,1);  //将链表中位置4上的元素修改为1
        printList(pList);
     
        insertHeadList(&pList,5);   //表头插入元素12
        printList(pList);
     
        insertLastList(&pList,10);  //表尾插入元素10
        printList(pList);
     
        clearList(pList);       //清空链表
        system("pause");
         
    }
    
    

    单链表的基本操作大全之C语言实现

    1. 单链表的定义

    链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单元可以是连续的也可以是不连续的。为了建立起数据元素之间的关系,对于每个数据元素除了存放数据元素自身的信息外,还必须有包含的指示该元素直接后继元素存储位置的信息,这两部分信息组成一个结点,即每个结点都有至少包括两个域,一个域存储数据元素信息,称为数据域,另一个域存储直接后继的地址,称为指针域。

        typedef struct node{
            int data;    //数据域
            struct node *next;    //指针域
        }NODE;
    
    

    当n个元素的线性表通过每个结点的指针域连接成了一条“链子”,我们形象的称之为链表。

    2. 建立单链表

    建立单链表有两种方法,一种是头插法,一种是尾插法。
    在主函数中调用函数时,使用一个NODE *类型的指针接收函数的返回值。

    2.1初始化一个链表结点

    每次malloc的结点都要初始化,因此写成一个函数。

        //初始化一个节点
        NODE *initnode(NODE *pnode, int data)
        {
                pnode = (NODE *)malloc(sizeof(NODE));
                pnode->data = data;//初始化数据域
                pnode->next = NULL;//初始化指针域为NULL
    
                return pnode;
        }
    

    2.2头插法建立链表

    在链表的头部插入结点建立单链表,称为“头插法”。

        //创建一个新节点(头插法)
        NODE *createlink_byhead(NODE *phead, int data)
        {
                NODE *pnode = initnode(pnode, data);//初始化一个结点
                NODE *ptmp = phead;
    
            if(NULL == phead){    //链表为空,直接返回初始化的结点
                    return pnode;
            }else{
                    phead = pnode;    //将新申请的结点插在phead后面,也就是整个链表的最前面
                    pnode->next = ptmp;
            }
    
            return phead;
    }
    

    因为每次新结点都会插在链表的头部,则数据读入的顺序和线性表中的逻辑顺序正好相反。

    2.3尾插法建立链表

    在链表的尾部插入结点建立单链表,简称”尾插法“。

        //创建一个链表节点(尾插法)
        NODE *createlink_bytail(NODE *phead, int data)
        {
                NODE *pnode = initnode(pnode, data);//初始化结点
                NODE *ptmp = phead;
    
            if(NULL == phead){//当链表为空,直接返回初始化的结点
                    return pnode;
            }else{
                    while(ptmp->next != NULL){//找到最后一个结点,插在尾部
                            ptmp = ptmp->next;
                    }
                    ptmp->next = pnode;
            }
    
            return phead;
        }
    

    尾插法读入的数据与线性表中的逻辑顺序相同

    3. 链表的长度

        //求链表长度
        int linklen(NODE *phead)
        {
                int len = 0;//计数器
                NODE *ptmp = phead;
    
                while(ptmp != NULL){//遍历链表,计数器加1
                        len++;
                        ptmp = ptmp->next;
                }
    
                return len;
        }
    

    这个算法的时间复杂度为O(n)

    4. 按值查找操作

       //按值查找
        NODE *searchnode(NODE *phead, int key)
        {
            NODE *ptmp = phead;
    
            if(NULL == phead){    //链表为空,直接返回
                    return NULL;
            }
            while(ptmp->data != key && ptmp->next != NULL){//没找到key && 链表没找完
                    ptmp = ptmp->next; //指针移动
            }
            if(ptmp->data == key) //找到key,返回该结点地址
                    return ptmp;
            if(ptmp->next == NULL)//没找到,返回空
                    return NULL;
        }
    

    这个算法的时间复杂度为O(n)

    5.插入操作

    插入操作也分为两种,一种是插在目标值得前面,简称“前插法”,另一种是插在目标值的后面,简称“后插法”。

    5.1前插法

     //向前插入
        NODE *insertnode_bypre(NODE *phead, int data, int key)
        {
            NODE *pnode = initnode(pnode, data);//初始化插入的结点
            NODE *ptmp = phead;
    
            if(NULL == phead){//链表为空,直接返回初始化的结点
                    return pnode;
            }else if(phead->data == key){//处理第一个结点是否为目标结点
                    phead = pnode;
                    pnode->next = ptmp;
            }else{
                    while(ptmp->next != NULL && ptmp->next->data != key){//循环遍历,没找完 && 没找到
                            ptmp = ptmp->next;
                    }
                    if(NULL == ptmp->next){//没找到的情况
                            printf("insert key NOT FOUND
    ");
                    }else{//把新节点插入目标结点的前面
                            ptmp->next->data == key;
                            pnode->next = ptmp->next;
                            ptmp->next = pnode;
                    }
            }
            return phead;
        }
    

    前插法单独处理了第一个结点,是因为前插法会改变phead的值,而且前插法查找目标结点必须知道目标节点的前驱结点的next值,所以从第二个结点开始处理。

    5.2后插法

       //向后插入
        NODE *insertnode_byback(NODE *phead, int data, int key)
        {
            NODE *pnode = initnode(pnode, data);//初始化插入的结点
            NODE *ptmp = searchnode(phead, key);//查找到目标结点
    
            if(NULL == ptmp){//处理链表为空,或没找到
                    printf("link is empty or not found key
    ");
                    return phead;
            }
            if(NULL == ptmp->next){//如果key为最后一个结点
                    ptmp->next = pnode;
            }else{ //将新节点插入在目标结点的后面
                    pnode->next = ptmp->next;
                    ptmp->next = pnode;
            }
    
            return phead;
    }
    

    后插法要单独处理尾结点的情况,因为插入操作不相同。
    前插法和后插法的时间复杂度都为O(n)

    6.删除操作

      //删除节点
        NODE *delnode(NODE *phead, int key)
        {
            NODE *ptmp = phead;
            NODE *tmp = NULL;
    
            if(NULL == phead){//处理链表为空的情况
                    printf("link is empty, del fail
    ");
                    return NULL;
            }else if(phead->data == key){//单独处理第一个结点
                    phead = phead->next;
                    free(ptmp);
                    ptmp = NULL;
            }else{
                    while(ptmp->next != NULL && ptmp->next->data != key){ //没找完 && 没找到
                            ptmp = ptmp->next;
                    }
                    if(NULL == ptmp->next){ //没找到
                            printf("del key NOT FOUND
    ");
                            return phead;
                    }
                    if(ptmp->next->data == key){ //找到目标结点删除之
                            tmp = ptmp->next;
                            ptmp->next = tmp->next;
                            free(tmp);
                            tmp = NULL;
                    }
            }
            return phead;
    }
    

    单独处理第一个结点还是因为要知道要删除目标结点的前驱结点
    删除操作算法时间复杂度为O(n)

    7.链表的倒置

    链表的倒置算法思路:一次取出原链表中的每一个结点,将其作为第一个结点插入新链表中。

      //链表的倒置
        NODE *reverselink(NODE *phead)
        {
            NODE *ptmp = NULL;//创建一个新链
            NODE *tmp = NULL;
    
            if(NULL == phead){//处理链表为空
                    printf("link is empty
    ");
                    return NULL;
            }else{
                    while(phead != NULL){//将旧链上的结点链到新链上
                            tmp = phead;
                            phead = phead->next;
                            tmp->next = ptmp;
                            ptmp = tmp;
                    }
            }
            return ptmp;
    }
    

    8.链表的排序(冒泡排序)

        //链表排序(冒泡)
        NODE *linksort(NODE *phead)
        {
            NODE *p = NULL; //i
            NODE *q = NULL; //j
            NODE *r = NULL; 
            NODE tmp; 
    
            for(p = phead; p; p = p->next){
                    for(q = p->next; q; q = q->next){
                            if(p->data > q->data){
                                    tmp = *p;//整个结点交换
                                    *p = *q;
                                    *q = tmp;
                                    r = p->next;//将指针换回去
                                    p->next = q->next;
                                    q->next = r;
                            }
                    }
            }
    
            return phead;
        }
    

    冒泡排序的时间复杂度为O(n²)

  • 相关阅读:
    Zookeeper系列(二)特征及应用场景
    Scala学习笔记(三)类层级和特质
    zookeeper系列(一)安装
    Scala学习笔记(二)表达式和函数
    Spring笔记(四)SpingAOP
    Spring笔记(三)AOP前篇之动态代理
    Scala学习笔记(一)数据类型
    Linux内核系列设备模型(一) Kobject与Kset
    Spring笔记(二)Core层
    Linux内核系列之Block块层(一)
  • 原文地址:https://www.cnblogs.com/muahao/p/7471425.html
Copyright © 2020-2023  润新知