单链表操作(无头节点)

#ifndef SINGLELIST_H
#define SINGLELIST_H

/ 这是没有头结点的版本文件 //
/ 有头结点的版本更简单些,操作统一 //

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
typedef int ElemType;

typedef struct Node{
    ElemType data;
    struct Node *next;
}Node,*LinkList;

// 分配新节点并初始化
LinkList NewNode(void)
{
    LinkList new = (LinkList)malloc(sizeof(struct Node));
    if (new)
        memset(new, 0, sizeof(*new));
    return new;
}
void ListInfo(LinkList list)
{
    LinkList pos = list;
    if (!list){
        printf("ListInfo: NULL\n");
        return;
    }
    printf("ListInfo:\n");
    while(pos){
        printf("%d, ",pos->data);
        pos = pos->next;
    }
    printf("\n");
}
// 在单链表list的第i个节点前插入节点e
int ListInsert(LinkList *list, int i, ElemType e)
{
    /* 前提条件: list已经存在,并且i没有超出链表的范围 */
    LinkList pos = *list;
    LinkList new = NewNode();
    new->data = e;

    // 插入到链表的最前面,头指针改变。
    if (i == 1){
        new->next =  pos;
        *list = new; // 头指针改为新插入的节点
    }
    // 插入到链表头指针后面,头指针不改变
    else{
        // 1 2 4==> 1 2 3 4
        //   i=3
        for(int k=1; k <= i-1-1; k++){
            if(!pos) // 插入位置前面的一个节点不存在,无法插入.
                return -1;
            pos = pos->next;
        }
        new->next = pos->next;
        pos->next = new;
        //printf("pos=%p, pos->next=%p\n",pos,pos->next);
    }
    return 0;
}
// 删除单链表list的第i个节点,并将该节点的数据域返回给e。
int ListDelete(LinkList *list, int i, ElemType *e)
{
    LinkList pos = *list;    // 链表头指针

    if (i == 1){                // 删除头指针
        if (e)
            *e = pos->data;
        if (!pos->next)         // 只有头指针,不允许删除。
            return -1;
        *list = pos->next;   // 链表头指针 = 链表头指针的下一项
        free(pos);
    }
    else{               // 删除非头指针
        // 1 2  => 1, i=2
        for(int k=1; k <= i-1-1; k++){
            if(!pos) // 插入位置前面的一个节点不存在,无法插入.
                return -1;
            pos = pos->next;
        }
        // pos为删除位置的前一项
        if (e)
            *e = pos->next->data;
        LinkList del = pos->next;       // 被删除的元素
        pos->next = del->next;
        free(del);
    }
    return 0;
}

void Listfree(LinkList *list)
{
    LinkList head;
    while(*list) {
        head = *list;   // 头指针
        *list = head->next; // 头指针=头指针的下一项
        free(head);      // 释放头指针
        printf("head=%p\n", head);
    }
    //*list = NULL;
}

// 链表最前面插入新元素,链表没有头结点。
void ListAddHead(LinkList *list, LinkList new)
{
    new->next = *list;
    *list = new;
}

// 创建带有n个节点的链表,没有头结点
LinkList ListCreate(int n)
{
    LinkList list = NewNode();
    if (!list)
        return NULL;
    srand(time(0));
    list->data = rand()%1000+1;    // 1000的随机数
    for (int i=1; i <=n-1; i++){

        LinkList new = NewNode();
        new->data = rand()%1000+1;    // 1000的随机数
        if (!new){
            Listfree(&list);
            return NULL;
        }
        ListAddHead(&list,new);
    }
    return list;
}

// 快速找出链表的中间节点,返回节点的序号
int ListMidNode(LinkList list)
{
    /* // 快慢指针法
    1.设置两个指针 *search,*mid,都指向单链表的头结点。
    2.其中*serch的移动速度是*mid的两倍。
    3.先让*search先走。
      如果*search后面有两个节点以上(节点总数为奇数),那么*search移动两步,*mid移动一步;
      如果*search后面只有一个节点(节点总数为偶数),那么*search移动一步,mid不移动;
      如果*search后面没有节点时,那么搜索结束。
    4.*search指向末尾节点的时候,mid正好就在中间了。
        //例子//
        1  2  3  4  5  6  7	// 链表节点
        ms	 				// 第一次搜索
           m  s				// 第二次搜索
              m 	s
                 m	      s // 第三次搜索
    */
    LinkList mid,search;
    mid = search = list; //指向开始位置
    int midPos=1;
    while(search->next){
        if (search->next->next){
            search = search->next->next;
            mid = mid->next;
            midPos++;
        }
        else{
            search = search->next;
        }
    }
    return midPos;
}

// 不分配新空间,逆序链表。
void ListReverse(LinkList *list)
{
    /* p1(head prePos) p2(pos)          p3     // head = p1, prePos=p1, pos=p2
     * p2(head)        p1(prePos)       p3     // head = p2, prePos=p1, pos=p3
     * p3(head)        p2               p1(prePos)    (NULL)pos      // head = p3, prePos=p1, pos=NULL
        步骤: 1.从第二项开始循环往前挪动元素,pos为NULL时结束。
                 1.从链表中断开pos节点
                 2.将pos节点插入到链表头部
             2.重新赋值链表的头指针
    */
    LinkList head   = *list;
    LinkList pos = head->next;
    LinkList posPre = head;    // pos的前一项
        // pos的前一项
    while (pos){
        posPre->next = pos->next;   /* 1.从链表中断开pos节点 */
        pos->next = head;           /* 2.将pos节点插入到链表头部 */
        head = pos;
        // posPre往后移了一项,所以pos = posPre的下一项
        pos = posPre->next;
    }
    /* 重新赋值链表的头指针 */
    *list = head;
}
#endif // SINGLELIST_H

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值