数据结构之单链表

链表:存储结构的一种,包含两个部分,数据域和指针域,相对于顺序存储结构来说,插入和删除的算法时间复杂度只为O(1).

定义:

//定义
typedef struct Node *LinkList;   //linkList,指针指向每一个元素


typedef struct Node{          //每个元素的构成 

    ElemType data;              //数据域 
    struct Node *next;          //指针域 

}Node; 

注意:假设结点p表示一个结点A,那么p->next表示的下一个结点B,p->next也表示结点A的指针域,故,指针域存放的是指向下一个结点的指针。

以下为简单的C语言实现:

#include "stdio.h"    
#include "string.h"
#include "ctype.h"      
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"


#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 存储空间初始分配量 */

typedef int Status;
typedef int ElemType;

//定义
typedef struct Node *LinkList;   //linkList,指针指向每一个元素


typedef struct Node{          //每个元素的构成 

    ElemType data;              //数据域 
    struct Node *next;          //指针域 

}Node; 



//初始化
Status InitList(LinkList *L){

    *L = (LinkList)malloc(sizeof(Node));    //产生头结点,使得L指向分配到的头结点

    if(!(*L)){
        //如果分配失败 
        return ERROR;
    } 

    (*L)->next = NULL;//指针域为空

     return OK; 
} 

//获取第几个元素 
Status GetElem(LinkList L,int i,ElemType *e)
{
    int j;
    LinkList p;     /* 声明一结点p */
    p = L->next;        /* 让p指向链表L的第一个结点 */
    j = 1;      /*  j为计数器 */
    while (p && j<i)  /* p不为空或者计数器j还没有等于i时,循环继续 */
    {   
        p = p->next;  /* 让p指向下一个结点 */
        ++j;
    }
    if ( !p || j>i ) 
        return ERROR;  /*  第i个元素不存在 */
    *e = p->data;   /*  取第i个元素的数据 */
    printf("第%d元素为%d\n",i,*e);
    return OK;
}

//判断是否为空
Status isEmptyList(LinkList L){

    if(L->next){
        return 1;
    }else{
        return 0; 
    }

} 

//获取链表的长度
int ListLength(LinkList L){
    int i=0;
    LinkList p ;
    p = L->next;

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

    return i;

} 


//遍历链表
 Status ListVisit(LinkList L){
    LinkList p = L->next;

    printf("该链表的元素为:\n");
    while(p){
        printf("%d ",p->data);
        p = p->next;
     }

     printf("\n");

     return OK;
 }

//创建表,两种方法,头插法和尾插法 

//头插法,在每一个头的开始不段插入,例如我们插入0-9,那么输出的结果就是9-0 
void CreateListHead(LinkList *L,int n){

    LinkList p;
    int i;
    srand(time(0));
    *L = (LinkList)malloc(sizeof(Node));
    (*L)->next = NULL;                   //先建立一个带头结点的单链表

    for(i=0;i<n;i++){

        p = (LinkList)malloc(sizeof(Node));      //新结点 
        p->data = rand()%100+1;                  //随机生成100以内的数字 
        p->next = (*L)->next;                   

        (*L)->next = p;                        //插入到头结点 ,即就是插入操作    
    } 


}


//尾插法  ,最末尾元素后面插入,插入0-9 输出0-9 
void CreateListTail(LinkList *L,int n){

    LinkList p,r;
    int  i;
    srand(time(0));

    *L = (LinkList)malloc(sizeof(Node));

    r = *L;                 //r指向链表 

    for(i=0;i<n;i++){
        p = (Node *)malloc(sizeof(Node));
        p->data = rand()%100+1;

        r->next = p;         /* 将表尾终端结点的指针指向新结点 */
        r = p;              //将r赋值为新节点,下次指向的时候也就是把r指向了最末尾的结点,那么r也就是最末尾的结点 
    }

    r->next = NULL;         //表示当前链表结束 

} 

//重置表,也就是一个个结点的释放 
Status ListClear(LinkList *L){

    LinkList p,q;

    p = (*L)->next;
    while(p){
        q = p->next;   //每一次指向然后释放 
        free(p);

        p = q;         // 释放后    重新赋给其原来的q结点的位置 
    }

    (*L)->next = NULL;     //头结点指针域赋值为空 
    printf("清空完成\n");
    return OK;


}


//查找表中元素
int LocateEle(LinkList L,ElemType e){
    int i=0;
    LinkList p;
    p = L->next;          //指向链表,也就会指向头结点

    while(p){
        i++;
        if(p->data == e){
            printf("元素%d在第%d个位置\n",e,i); 
            return i;
        }

        p = p->next;
    } 


    return 0;

}

//插入元素到表
Status ListInsert(LinkList *L,int i,ElemType e){

    int j;
    LinkList p,s;               //创建两个结点p  s
    p = *L;                     //指向一个链表

    j=1;
    //查找到第i个结点 
    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的后继结点赋给s的 后继 

    p->next = s;                         //将s赋给p的后继 ,注意以上两条语句的位置不能倒置

    return OK;
} 

//删除表中元素 
Status ListDelete(LinkList *L,int i,ElemType *e){

    int j;
    LinkList p,q;

    p = *L;
    j=1;

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

    if(!(p->next)  || j>i){
        return ERROR;
    }
    q = p->next;             //先将p的后继赋给一个我们设置为q的结点,这个结点就是我们要删除的 

    p->next = q->next;       //将原来q的后继赋给p的后继 
    *e = q->data;            //将要删除的元素的值赋给*e 

    printf("删除的元素为%d:\n",*e);

    free(q);                //记得free 

    return OK;
}



int main(){

    LinkList L;
    ElemType e;
    Status i;
    int j,k;

    //初始化链表
    i = InitList(&L);
    printf("初始化完成后插入的链表为\n");
    for(j=1;j<=5;j++){
        ListInsert(&L,1,j);
    }

    ListVisit(L);

    //插入单个元素
    ListInsert(&L,2,100);
    e = 100;
    LocateEle(L,e);
    ListVisit(L);

    //删除元素
    ListDelete(&L,2,&e);

    ListVisit(L);

    //获取第几个元素
    GetElem(L,5,&e);

    //清空重置
    ListClear(&L);
    ListVisit(L);

    //头插法
    CreateListHead(&L,10);
        ListVisit(L);

    //尾插法 
     CreateListTail(&L,10);
        ListVisit(L);

    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值