不带头结点的单链表

单链表的结点:数据域,指针域(存储下一结点的地址)

包含函数:初始化,销毁,清空,尾插法和头插法批量录入数据,统计结点的个数,追加结点,删除结点,正序和逆序打印链表。

知识点:

(1)一个结构体内部不能含有结构体本身类型的结点,但可以含有本类型的指针。

(2)易错点:删除,插入的操作可能会影响首结点的地址,要单独处理,不注意代码运行会全是bug!

(3)逆序打印采用的递归,可着重看一下。

(4)批量录入数据有两种方法:头插法,链表的顺序和输入顺序正好相反。尾插法则正好相同。

(5)删除结点采用O(1)方法,分4种情况
•首结点&&最后一个结点:*L = null
•首结点&&不是最后一个结点:先保存下一结点的地址,用下一结点覆盖本应删除的目的结点,删除事先保存的结点
•不是首结点&&最后一个结点:无法删除,必须采用伴随扫描指针的方式,获知前驱指针,才能删除
•不是首结点&&不是最后一个结点:采用情况2的方法

(6)伴随指针查找value的代码(两个紧邻指针一起扫描单链表,一般删除结点时使用)

//至少含有一个元素,即不为空

p = frist; q = NULL;

while (p != NULL && p->data != value)

{

    //在此通过p可以操作所有的元素

    q = p;/*这两个语句是不可分割的,是一个整体,相当于原语*/

    p = p->next;/*在这个整体前后,q一定指向p的前驱*/

    //在此p:2 to last;q:1 to last - 1

}

/*出循环后,q仍旧指向p的前驱,只要p不指向空*/

/*适用于查找value,并进行牵扯到其前驱的操作*/

注意第一个结点就是value的情况!,出循环后前驱指针是null

#include"头文件.h"
/*头插法,逆序
尾插法,正序*/
typedef struct node {
    int data;
    struct node *next;
}Node,*LinkList;
/*初始化单链表*/
void InitList(LinkList *L) {
    *L = null;
}
/*销毁单链表*/
void DestroyList(LinkList *L) {
    if (*L == null)
        return;
    LinkList p;
    while (*L != null) {
        p = (*L)->next;//临时保存下一结点的地址
        free(*L);
        *L = p;
    }
}
/*清空单链表*/
void ClearList(LinkList *L) {
    DestroyList(L);
}
/*批量录入数据:头插法*/
void HeadCreate(LinkList *L) {
    int elem; Node *p;
    while (scanf_s("%d", &elem), elem != -1) {
        if (*L == null) {
            *L = (LinkList)malloc(sizeof(Node));
            if (*L == null) exit(-1);
            (*L)->data = elem;
            (*L)->next = null;
        }
        else {
            p = (LinkList)malloc(sizeof(Node));
            if (!p) exit(-1);
            p->data = elem;
            p->next = (*L)->next;
            (*L)->next = p;
        }
    }
}
/*批量录入数据:尾插法*/
void TailCreate(LinkList *L) {
    int elem; Node *tail = null,*p;
    while (scanf_s("%d", &elem), elem != -1) {
        if (*L == null) {
            *L = (LinkList)malloc(sizeof(Node));
            if (*L == null) exit(-1);
            (*L)->data = elem;
            (*L)->next = null;
            tail = *L;
        }
        else {
            p = (LinkList)malloc(sizeof(Node));
            if (!p) exit(-1);
            p->data = elem;
            p->next = null;
            tail->next = p;
            tail = p;
        }
    }
}
/*统计结点的个数*/
int TotalNum(LinkList *L) {
    int count = 0;//计数器
    LinkList p = *L;
    for (; p; p = p->next)
        ++count;
    return count;
}
/*在表尾追加元素value*/
void AddToTail(LinkList *L,int value) {
    Node *p = null,*q = null;
    if (*L == null) {
        *L = (LinkList)malloc(sizeof(Node));
        if (*L == null) exit(-1);
        (*L)->data = value;
        (*L)->next = null;
    }
    else {
        for (p = *L; p->next != null; p = p->next)
            ;
        q = (LinkList)malloc(sizeof(Node));
        if (!q) exit(-1);
        q->data = value;
        q->next = p->next;
        p->next = q;
    }
}
/*删除第一个值是value结点*/
void Remove(LinkList *L,int value) {
    if (*L == null)
        return;
    Node *p = *L,*q;
    while (p && p->data != value) {
        p = p->next;
    }
    if (!p) {
        printf("没有该元素!\n"); return;
    }
    if (p == *L) {
        if (p->next == null) {
            *L = null;
            free(p);
        }
        else {
            p = (*L)->next;
            (*L)->data = (*L)->next->data;
            (*L)->next = (*L)->next->next;
            free(p);
        }
    }
    else {
        if (p->next != null) {
            p->data = p->next->data;
            q = p->next;
            p->next = q->next;
            free(q);
        }
        else {
            printf("无法删除,请采用伴随扫描指针的方法删除。\n");
            return;
        }
    }

}
/*打印单链表*/
void Print(LinkList *L) {
    if (*L == null)
        return;
    Node *p = *L;
    for (; p; p = p->next) {
        printf("%d ", p->data);
    }
    printf("\n");
}
/*递归逆序打印单链表*/
void FromTailPrint(LinkList *L) {
    if (*L == null)
        return;
    FromTailPrint(&(*L)->next);
    printf("%d ", (*L)->data);
}
int main() {
    LinkList L;
    InitList(&L);
    TailCreate(&L);
    fflush(stdin);
    printf("打印单链表\n");
    Print(&L);
    printf("单链表结点的个数是:%d\n", TotalNum(&L));
    printf("删除9\n");
    Remove(&L, 9);
    printf("打印单链表\n");
    Print(&L);
    printf("追加10\n");
    AddToTail(&L, 10);
    printf("逆序打印单链表\n");
    FromTailPrint(&L);
    system("pause");
    return 0;
}

猜你喜欢

转载自www.linuxidc.com/Linux/2017-11/148720.htm