单链表-不带头结点

2020-03-27  本文已影响0人  又是一只小白鼠

链表,别名链式存储结构或单链表,用于存储逻辑关系为 "一对一" 的数据。与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其物理存储位置是随机的。

链表中数据元素的构成

每个元素本身由两部分组成:

这两部分信息组成数据元素的存储结构,称之为“结点”。n个结点通过指针域相互链接,组成一个链表。

typedef int ElemType;
typedef struct LinkNode
{
    ElemType data;
    struct LinkNode *next;
}Node,*pNode;

//为新节点开辟空间 这个一块存储空间 包括一个数据域+一个指针域
pNode NewSpace(ElemType data)
{
    pNode tmp = (Node *)malloc(sizeof(Node));
    tmp->data = data;
    tmp->next = NULL;
    return tmp;
}

头结点、头指针和首元结点

头结点和头指针的区别:头指针是一个指针,头指针指向链表的头结点或者首元结点;头结点是一个实际存在的结点,它包含有数据域和指针域。两者在程序中的直接体现就是:头指针只声明而没有分配存储空间,头结点进行了声明并分配了一个结点的实际物理内存

单链表初始化

//初始化
void InitNodeList(pNode *pHead) {
    *pHead = NULL;
}

尾插

//尾插
void InsertNodeBack(pNode *pHead, ElemType e) {
    assert(NULL != pHead);
    pNode temp = *pHead; //创建临时结点temp
    //判断节点是否为空,如果为空就给让分配空间
    if (*pHead == NULL) {
        *pHead = NewSpace(e);
    }
    else {
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = NewSpace(e);
    }
}

首插

//头插
void InsertNodeFront(pNode *pHead, ElemType e) {
    assert(NULL != pHead);
    pNode temp; //创建临时结点temp
    temp = NewSpace(e);
    temp->next = *pHead;
    *pHead = temp;
}

尾删

//尾删
void RemoveNodeBack(pNode *pHead) {
    assert(NULL != pHead);
    pNode temp = *pHead;
    if (temp == NULL) {
        printf("Seqlist is Empty...\n");
        return;
    }
    else if (temp->next == NULL) {
        free(temp);
        *pHead = NULL;
    }
    else {
        temp = *pHead;
        pNode pre = NULL;
        while (temp->next != NULL) {
            pre = temp;
            temp = temp->next;
        }
        pre->next = NULL;
        free(temp);
        temp->next = NULL;
    }
}

首删

//首删
void RemoveNodeFront(pNode *pHead) {
    assert(pHead);
    pNode temp = *pHead;
    if (temp == NULL) {
        printf("Seqlist is Enpty...\n");
        return;
    }
    else if(temp->next == NULL) {
        *pHead = NULL;
        free(temp);
    }
    else {
        *pHead = temp->next;
        free(temp);
    }
}

删除指定位置节点

//指定位置删除
void RemoveNodePos(pNode *pHead, int pos) {
    assert(pHead);
    pNode pre = *pHead;
    if (pos == 1) {
        *pHead = pre->next;
        free(pre);
    }
    else {
        for (int i=1; i<pos-1; i++) {
            pre = pre->next;
            if(pre == NULL) {
                printf("找不到要删除的坐标,超过了最大长度...\n");
                return;
            }
        }
        pNode cur = pre->next;
        pre->next = cur->next;
        free(cur);
    }
}

在指定位置插入节点

//指定位置插入
void InsertNodePos(pNode *pHead, ElemType data, int pos) {
    assert(pHead);
    pNode pre = *pHead;
    if (pos == 1) {
        pNode temp = NewSpace(data);
        *pHead = temp;
        temp->next = pre;
        *pHead = temp;
    }
    else {
        for (int i=1; i<pos-1; i++) {
            pre = pre->next;
            if (pre == NULL) {
                printf("找不到,超足了链表最大长度...\n");
                return;
            }
        }
        pNode cur = NewSpace(data);
        cur->next = pre->next;
        pre->next = cur;
    }
}

删除链表中所有值为data的节点

//删除所有data的值
void RemoveNodeDataAll(pNode *pHead, ElemType data) {
    assert(pHead);
    pNode pre = *pHead;
    //只有一个元素并且值为要找的元素
    if (pre->data == data && pre->next == NULL) {
        free(pre);
        *pHead = NULL;
        return;
    }
    pNode cur = *pHead;
    while (1) {
        if (pre && pre->data == data && pre->next != NULL && pre->next->data != data) {
            *pHead = pre->next;
            free(pre);
            pre = *pHead;
        }
        while (pre && pre->data != data) {
            cur = pre;
            pre  = pre->next;
        }
        if (pre && pre->data == data && pre->next != NULL) {
            cur->next = pre->next;
            free(pre);
            pre = cur->next;
        }
        else if(pre && pre->data == data && pre->next != NULL) {
            cur->next = NULL;
            free(pre);
            pre = cur;
        }
        else {
            return;
        }
    }
}

获取节点长度

//计算链表长度
int NodeLength(pNode pHead) {
    assert(pHead);
    int count = 0;
    pNode pre = pHead;
    while (pre) {
        count ++;
        pre = pre->next;
    }
    return count;
}

打印

//打印链表
void PrintNodeList(pNode pHead) {
    assert(pHead);
    pNode temp = pHead; //创建临时结点temp
    while (temp != NULL) {
        printf("%d\t", temp->data);
        temp = temp->next;
    }
    printf("\n");
}

逆置1

//逆置,从头到尾访问旧的链表,每访问一个,
//就将节点的数据采取头插的方式存入新的链表,释放原来链表的空间
void ReverseNode1(pNode *pHead) {
    assert(pHead);
    pNode pre = *pHead;
    pNode new = NULL;
    while (pre) {
        pNode cur = pre;
        pNode temp = NewSpace(pre->data);
        temp->next = new;
        pre = pre->next;
        new = temp;
        free(cur);
    }
    *pHead = new;
}

逆置2

//逆置,从头到尾访问旧的链表,每访问一个就把这个节点插到新的链表中
void ReverseNode2(pNode *phead) {
    assert(phead);
    pNode pre = *phead;
    pNode new = NULL;
    while (pre) {
        pNode cur = pre;
        pre = pre->next;
        cur->next = new;
        new = cur;
    }
    *phead = new;
}

逆置3

//链表逆置
void ReverseNode3(pNode *phead) {
    assert(phead);
    pNode temp = *phead;
    pNode temp_pre = NULL;
    pNode temp_next = NULL;
    if (temp->next == NULL) {
        return;
    }
    else if(temp->next->next == NULL) {
        return;
    }
    while (temp) {
        temp_next = temp->next;// 保存当前节点的下一个节点
        temp->next = temp_pre;//更新当前节点的指针域
        temp_pre = temp;//更新当前节点上一个节点的位置
        temp = temp_next;//更新当前节点的位置
    }
    *phead = temp_pre;
}

顺序表拼接1

//拼接C=A+B
void JointNodeNew(pNode *La, pNode *Lb, pNode *Lc) {
    pNode pa = *La;
    pNode pb = *Lb;
    pNode pc = *Lc;
    if (pa && pb == NULL) {
        *Lc = pa;
        return;
    }
    if (pb && pa == NULL) {
        *Lc = pb;
        return;
    }
    if (pb->data <= pa->data) {
        pNode temp = pb;
        pb = pb->next;
        *Lc = temp;
        pc = *Lc;
    }
    else if (pb->data > pa->data) {
        pNode temp = pa;
        pa = pa->next;
        *Lc = temp;
        pc = *Lc;
    }
    while (pa && pb) {
        if (pa->data <= pb->data) {
            pc->next = pa;
            pc= pa;
            pa = pa->next;
        }
        else {
            pc->next = pb;
            pc= pb;
            pb = pb->next;
        }
    }
    pc->next = pa?pa:pb;
}

顺序表拼接2

//链接拼接 A = A+B temp->next = pa
//pa->next = NULL 说明temp是最后一个元素, 只需要把Lb拼接到La
//temp->next = pb;
//使用一个tmp指向Lb的头节tmp=pb;
//当要把pb的节点拼接到La,首先把头节点只想pb的下一个节点tmp=pb->next
//把pb插入到La中之后,再把pb指向Lb的头节点tmp
void JointNode(pNode *La, pNode *Lb) {
    assert(La);
    assert(Lb);
    pNode pa = *La;
    pNode pb = *Lb;
    pNode temp = pa;
    pNode tmp = pa;
    if (pa && pb == NULL) {
        *La = pa;
    }
    else if (pb && pa == NULL) {
        *La = pb;
    }
    if(pb->data < pa->data) {
        tmp = pb->next;
        *La = pb;
        temp = pb;
        pb->next = pa;
        pb = tmp;
    }
    while (pa && pb) {
        if (pa->data > pb->data) {
            tmp = pb->next;
            temp->next = pb;
            pb->next = pa;
            temp = pb;
            pb = tmp;
        }
        else {
            temp = pa;
            pa = pa->next;
        }
    }
    if (pb == NULL) {
        return;
    }
    if (pb != NULL) {
        pa->next = pb;
    }
}

约瑟夫环

//约瑟夫环(约瑟夫问题)是⼀个数学的应⽤问题:
// 已知n个⼈(以编号1, 2, 3...n分别表⽰)围坐在⼀张//圆桌周围。
// 从编号为k的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈又从k开始报数,数到m的那个⼈
// 又出列;依此规律重复下去,直到圆桌周围的⼈全部出列
//约瑟夫环
void NodeJosephCycle(pNode *pHead, int k) {
    assert(pHead);
    pNode cur = *pHead;
    //第一步,先让链表构成环,即需要一个变量(tail)遍历至最后一个节点,
    //然后让最后一个结点的next指向*phead
    pNode tail = *pHead;
    while (tail->next != NULL) {
        tail = tail->next;
    }
    tail->next = *pHead;
    //第二步,让链表从起始地址进行查询,找到k的位置,然后删掉这个结点,
    //从该结点的下一个结点继续找K个位置,再次删掉,直到剩一个结点为止
    //cur是我们要删除的结点,用pre来标识cur的上一个位置。
    while (cur->next != cur) {
        pNode pre = NULL;
        int i=0;
        for (; i<k-1; i++) {
            pre = cur;
            cur = cur->next;
        }
        pre->next = cur->next;
        printf("delete....%d\n", cur->data);
        free(cur);
        cur = pre->next;
    }
    printf("save...%d\n", cur->data);
    cur->next = NULL;
}
上一篇 下一篇

猜你喜欢

热点阅读