天地玄黄 发表于 2020-11-29 11:25

【笔记】带头节点的单链表的C语言实现

什么是线性表?
线性表就是一组数据的集合以某种特定方式排列。该排列方式中除第一个元素和最后一个元素外,每一个元素的前面和后面都有其他元素。第一个元素前面没有其他元素,最后一个元素后面没有其他元素。

线性表在计算机中有不同的存储方式,昨天我写的实现方式是顺序存储也就是说数据前后的数据在计算机的存储器中是一个一个挨着存的。今天的实现是单链表形式,数据在计算机中的存放位置仅仅是在逻辑上前后挨着,在计算机的存储器里并没有放在一起,数据之间通过指针实现逻辑上的互联。

一个线性表的单链表存储形式的存储形式如图:

该图中,head指向的为单链表的头结点,该单链表中有两个数据(数据没有在图上写出来,鼠标写字太难了{:301_971:} )。
从图中可以看出:

[*]链表中的每个节点包含一个数据和一个指针(指向下一个节点)。
[*]链表有一个头节点,不存储元素内容,头节点的指向存储第一个元素的结点。
[*]线性表为空时,头节点指针项为空(用0表示)。
[*]线性表不为空时,链表中存储最后一个元素的指针项为空,表示后面没有元素了。
[*]线性表元素从1开始标号。存储结构中,可以将头结点的编号视为0,实现逻辑编号与物理编号的统一。
[*]head指针指向头结点。

单链表实现:list.h
```c
typedef char EleType;
typedef struct node{
        EleType data;
        struct node * next;
} ChainNode;
typedef struct{
        ChainNode * head;
} List;
List * CreateList(void);
void DestroyList(List *);
void ClearList(List *);
int ListInsert(List *,int,EleType);
int ListDelete(List *,int);
int ListAppend(List *,EleType);
int TraverseList(List *,int (*)(EleType *));
int GetElement(List * l,int n,EleType * data);
ChainNode* NewChainNode(EleType);
ChainNode* GetAddr(List *,int );

List* CreateList(void){
        List * l = 0;
        ChainNode * p = 0;
        EleType * data = 0;
        l = (List *)malloc(sizeof(List));
        if(l == 0) return 0;
        p = NewChainNode(*data);
        if(p==0) return 0;
        l->head = p;
        return l;
}

void DestroyList(List * l){
        ClearList(l);
        free(l->head);
}

void ClearList(List * l){
        while(l->head->next){
                ListDelete(l,1);
        }
}

int ListInsert(List * l,int n,EleType data){
        ChainNode * p = 0;
        ChainNode * newp = 0;
        p = GetAddr(l,n-1);
        if( p == 0 ) return 0;
        newp = NewChainNode(data);
        if(newp == 0 ) return 0;
        newp->next = p->next;
        p->next = newp;
        return 1;
}

int ListDelete(List * l,int n){
        ChainNode * p = 0;
        ChainNode * temp = 0;
        p = GetAddr(l,n-1);
        if(p==0) return 0;
        temp = p->next;
        if(temp==0) return 0;
        p->next = temp->next;
        return 1;
}

int ListAppend(List * l,EleType data){
        ChainNode * p = 0;
        ChainNode * newp = 0;
        p = l->head;
        while(p->next)
                p = p->next;
        newp = NewChainNode(data);
        if(newp == 0 ) return 0;
        p->next = newp;
        return 1;
}

int TraverseList(List * l, int (*f)(EleType*data)){
        ChainNode * p = 0;
        int cnt = 0;
        EleType * temp =0;
        p = l->head->next;
        while(p){
                cnt++;
                temp = &(p->data);
                if(f(temp) == 0) return cnt;
                p = p->next;
        }
        return -1;
}

int GetElement(List * l,int n,EleType * data){
        ChainNode * p = 0;
        if(n < 1) return 0;
        p = GetAddr(l,n);
        if(p == 0) return 0;
        (*data)=p->data;
        return 1;
}

ChainNode * NewChainNode(EleType data){
        ChainNode * p = 0;
        p = (ChainNode *)malloc(sizeof(ChainNode));
        if(p == 0) return 0;
        p->data = data;
        p->next = 0;
        return p;
}

ChainNode * GetAddr(List * l,int pos){
        ChainNode * p = 0;
        int cnt = 0;
        p = l->head;
        if(pos < 0) return 0;
        while(p && cnt++ < pos){
                p = p->next;
        }
        if(cnt < pos) return 0;
        return p;
}
```

对list.h进行测试(检验程序的鲁棒性):m.c
```c
#include"list.h"

#define RIGHT 0
#define WRONG 1
#define CREATELIST 0
#define LISTAPPEND 1
#define LISTINSERT 2
#define LISTDELETE 3
#define GETELEMENT 4
#define CLEARLIST5
#define titleTest printf("your:");
#define titleSystem printf("\nsyst:");


int putE(EleType*);

void showResult(List*, int no, char *answer);


char* strArr[] =
{

   "---------CreateList Test---------",
   "---------ListAppend Test---------",
   "---------ListInsert Test---------",
   "---------ListDelete Test---------",
   "---------GetElement Test---------",
   "---------ClearList Test---------",   
};


main()
{

   char* arr = "assembly";

   int n = 0;
   List* list;
   char chArr = {0,0,0,0,0,0,0,0,0,0};
   char ch;

   list = CreateList();
   puts(strArr);
   if(!list) { puts("createList wrong!"); return; }
   else      { puts("createList no nullpointer!");}
   puts(""); getch();




   for(n=0; arr; n++) ListAppend(list, arr);
   showResult(list, LISTAPPEND, "assembly");


   ListInsert(list,1,'<');
   ListInsert(list,10,'>');
   ListInsert(list,7,'-');
   n = ListInsert(list,0,'0');
   n = n + ListInsert(list,13,'0');
   n = n + ListInsert(list,-1,'0');

   showResult(list, LISTINSERT, "<assem-bly>");
   if(n) puts("insert error!");




   n = 0;   
   ListDelete(list,1);
   ListDelete(list,10);
   ListDelete(list,6);
   ListDelete(list,8);
   ListDelete(list,1);
   ListDelete(list,5);

   n = ListDelete(list,0);
   n = n + ListDelete(list, 6);
   n = n + ListDelete(list, -1);
   showResult(list, LISTDELETE, "sseml");
   if(n) puts("list delete error!");



   n = 0;

   GetElement(list, 5, &ch); chArr = ch;
   GetElement(list, 1, &ch); chArr = ch;
   GetElement(list, 3, &ch); chArr = ch;
   n = GetElement(list, 6, &ch);
   

   puts(strArr);
   titleTest printf("%s",chArr);
   titleSystem puts("lse");
   if(n) puts("getelement error!");
   puts(""); getch();

   ClearList(list);
   showResult(list, CLEARLIST, "");


   
}


void showResult(List* list, int no, char *answer)
{
   puts(strArr);
   titleTest TraverseList(list,putE);
   titleSystem puts(answer);
   puts(""); getch();

}

int putE(EleType* e)
{
    printf("%c", *e);

    return 1;
}

```

ciker_li 发表于 2020-11-29 15:47

感谢分享
页: [1]
查看完整版本: 【笔记】带头节点的单链表的C语言实现