单链表以及静态链表的实现

注意:
我认为对于数据结构的深入理解并不是掌握书本上的概念,最重要的是自己的动手编写过程,其中有不少饶人的注意点,望读者有了基本了解之后,动手能够亲自实现,这是一个不一样的过程

**链表中的数据是以节点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
· 以“结点的序列”表示线性表称作线性链表(单链表)
· 单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。
· 因此,查找第 i 个数据元素的基本操作为:移动指针,比较 j 和 i
单链表
1、链接存储方法
链接方式存储的线性表简称为链表(Linked List)。
链表的具体存储表示为:
① 用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
② 链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))
注意:
链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。
2、链表的结点结构
┌───┬───┐
│data │next │
└───┴───┘
data域–存放结点值的数据域
next域–存放结点的直接后继的地址(位置)的指针域(链域)
注意:
①链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的。
②每个结点只有一个链域的链表称为单链表(Single Linked List)。
【例】线性表(bat,cat,eat,fat,hat,jat,lat,mat)的单链表示如示意图
3、头指针head和终端结点指针域的表示
单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
注意:
链表由头指针唯一确定,单链表可以用头指针的名字来命名。
终端结点无后继,故终端结点的指针域为空,即NULL。
4、单链表注意点
①LinkList和ListNode是不同名字的同一个指针类型(命名的不同是为了概念上更明确)
②*LinkList类型的指针变量head表示它是单链表的头指针
③ListNode类型的指针变量p表示它是指向某一结点的指针
5、编写过程应了解的函数
①生成结点变量的标准函数
p=( ListNode *)malloc(sizeof(ListNode));
//函数malloc分配一个类型为ListNode的结点变量的空间,并将其首地址放入指针变量p中
②释放结点变量空间的标准函数
free(p);//释放p所指的结点变量空间
③结点分量的访问
利用结点变量的名字*p访问结点分量
方法一:(*p).data和(*p).next
方法二:p-﹥data和p-﹥next
④指针变量p和结点变量*p的关系
指针变量p的值——结点地址
结点变量*p的值——结点内容
(*p).data的值——p指针所指结点的data域的值
(*p).next的值——*p后继结点的地址
*((*p).next)——*p后继结点
注意:
① 若指针变量p的值为空(NULL),则它不指向任何结点。此时,若通过*p来访问结点就意味着访问一个不存在的变量,从而引起程序的错误。
② 有关指针类型的意义和说明方式的详细解释
可见,在链表中插入结点只需要修改指针。但同时,若要在第 i 个结点之前插入元素,修改的是第 i-1 个结点的指针。
因此,在单链表中第 i 个结点之前进行插入的基本操作为:
找到线性表中第i-1个结点,然后修改其指向后继的指针

代码如下:

#include 
#include 
#include 
#define Error 0
#define Ok 1
typedef int  ElemType;
typedef int  Status;
typedef struct Node
{
    ElemType  data;
    struct Node *next;

}Node,*LinkList;

typedef struct Node* LinkList;

/**
 *  获得单链表的元素
 */
Status GetElem_L(LinkList L, int i, ElemType *e)
{
    //工作指针后移;
    int j = 1;
    LinkList p ;

    p = L->next;


    while (p && j < i) {
        p = p->next;
        ++j;
    }

    if (!p || j > i) {
        return Error;
    }

    *e = p->data;
    return Ok;

}

/**
 *  单链表的插入
 */
LinkList ListInsert(LinkList *L, int i, ElemType e)
{
    int j = 1;
    LinkList p,s;

    p = *L;

    while (p && j < i) {
        p = p->next;
        ++j;
    }

    if (!p || j > i) {
        return Error;
    }
    s = (LinkList)malloc(sizeof(Node));

    s->data = e;

    s->next = p->next;
    p->next = s;


    return *L;
}

/**
 *  单链表的删除
 */
LinkList ListDelete(LinkList *L, int i)
{
    int j = 1;
    LinkList p;

    p = *L;

    while (p && j < i) {
        p = p->next;
        ++j;
    }

    if (!p || j > i) {
        return Error;
    }

    p->next = p->next->next;

//    e = p->data;

    free(p->next);
    return *L;


}

/**
 *  单链表的整表创建
 动态生成
 (头插法)始终让新节点插在第一的位置
 */
LinkList CreatList_LH(LinkList L,int n)
{
    LinkList p;
    int i ;

    L = (LinkList)malloc(sizeof(Node));
    L->next = NULL;

    srand((unsigned)time(0));

    for (i = 0; i < n; i++) {
        p  = (LinkList)malloc(sizeof(Node));
        p->data = rand()%100 + 1;
        //printf("%d ",p->data);
        p->next = L->next;
        L->next = p;

    }

    return L;

}

/**
 *  尾插法
 */
LinkList CreatList_LD(LinkList *L,int n)
{
    LinkList p,r;
    int i ;


    srand((unsigned)time(0));

    *L = (LinkList)malloc(sizeof(Node));
    //L->next = NULL;
    r = *L;

    for (i = 0; i < n; i ++) {
        p = (LinkList)malloc(sizeof(Node));
        p->data = rand()%100 + 1;
        //printf("%d ",p->data);
        r->next = p;
        r = p;
    }

    r->next = NULL;

    return *L;
}

/**
 *  单链表的清除
 */
Status ClearList(LinkList L)
{
    LinkList q,p;

    p = L->next;

    while (p) {
        q = p->next;
        free(p);
        p = q;
    }

    L->next = NULL;
    return Ok;

}


Status LengthOfList(LinkList L)
{
    int length;

    while (L->next != NULL) {
        length++;
        L = L->next;

    }
    return length;
}

ElemType GetMidNode(LinkList *L)
{
    LinkList search,mid;

    mid = search = *L;
    while (search->next != NULL) {

    if (search->next->next != NULL) {

        search = search->next->next;
        mid = mid->next;
    }
    else
    {
        search = search->next;
        mid = mid->next;
    }
    }

    return mid->data;
}

int main()
{

    LinkList list,start;

    /*  printf("请输入单链表的数据:");
     list = LinkedListCreatH();
     for(start = list->next; start != NULL; start = start->next)
     printf("%d ",start->data);
     printf("/n");
     */  printf("请输入单链表的个数:");
    int j = 0;
    scanf("%d",&j);

    list = CreatList_LD(&list, j);
    for(start = list->next; start != NULL; start = start->next)
        printf("%d ",start->data);

    printf("\n");

    int length = LengthOfList(list);
    printf("%d",length);

    printf("\n");
    int i;
    ElemType x;


    printf("请输入插入数据的位置:");
    scanf("%d",&i);


    while (i > j||i <= 0) {
        printf("请输入插入数据的位置:");
        scanf("%d",&i);
    }
    printf("请输入插入数据的值:");
    scanf("%d",&x);
    list = ListInsert(&list, i, x);
    for(start = list->next; start != NULL; start = start->next)
            printf("%d ",start->data);

     printf("\n");
    ElemType k;
    k =  GetMidNode(&list);
    printf("%d",k);


    printf("\n");
    printf("请输入删除数据的位置:");
    scanf("%d",&i);
    list = ListDelete(&list, i);
    for(start = list->next; start != NULL; start = start->next)
    {   printf("%d ",start->data);}
    printf("\n");


    ClearList(list);

    return 0;
}

**用数组描述的链表,即称为静态链表。
· 在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标cur。

· 这种存储结构,仍需要预先分配一个较大的空间,但在作为线性表的插入和删除操作时不需移动元素,仅需修改指针,故仍具有链式存储结构的主要优点。

#include 
#include 
#include 
#define MaxSize 100
typedef int  ElemType;
typedef struct {
    ElemType data;
    int cur;

}SList,StaticLinkList[MaxSize];

/**
 *  初始化
 */
void init_sl(StaticLinkList space)
{
    int i;
    for (i = 0; i < MaxSize - 1; i++) {
        space[i].cur = i +1;
    }

    space[MaxSize-1].cur = 0;
}

/**
 *  分配空闲结点
 */

int malloc_sl(StaticLinkList space)
{
    int i = space[0].cur;
    if (i) {
        space[0].cur = space[i].cur;
    }
    return i;
}

int GetListLength(StaticLinkList space)
{
    int j = 0;
    int k = space[MaxSize - 1].cur;
    while (k) {
        j++;
        k = space[k].cur;
    }
    return j;
}


void ListInsert(StaticLinkList L, int i, ElemType e)
{

    int k = MaxSize - 1;

    if (i < 1|| i > GetListLength(L) + 1) {
        return;
    }

    int v = malloc_sl(L);
    {

    for (int j= 0 ; j < i- 1; j++) {
        k = L[k].cur;//插入的前一个结点
    }
        L[v].data = e;
        L[v].cur = L[k].cur;
        L[k].cur = v;
    }
}

void Free_SLL(StaticLinkList L,int j)
{
    L[j].cur = L[0].cur;
    L[0].cur = j;
}
/**
 *  删除i位置的元素
 */
void DeleteList(StaticLinkList L, int i)
{
    int k = MaxSize - 1;

    if (i < 1|| i > GetListLength(L) + 1) {
        return;
    }

    for (int j = 0; j < i -1; j++) {
        k = L[k].cur;
    }

    int  temp = L[k].cur;
    L[k].cur = L[temp].cur;
    Free_SLL(L, temp);
}



void Print(StaticLinkList L) //打印链表
{
    int k = L[MaxSize - 1].cur;
    while(k)
    {
        printf("%d ",L[k].data);
        k = L[k].cur;
    }
    printf("\n");
}


int main(int argc, const char * argv[]) {

    srand((unsigned)time(0));

    StaticLinkList L;
    init_sl(L); //初始化链表
    for(int i = 0;i < 8;++i)
        ListInsert(L, i, rand()%100 + 1);
    Print(L); //输出链表


    int i,j;
    printf("请输入插入的位置:");
    scanf("%d",&j);
    printf("请输入插入的值:");
    scanf("%d",&i);
    ListInsert(L,j,i); //在链表的第3个位置插入22
    Print(L);


    printf("请输入删除的位置:");
    scanf("%d",&j);
    DeleteList(L,j);
    Print(L);
    return 0;
}

你可能感兴趣的:(C/C++)