数据结构--单向链表C实现

链表是非常重要的数据结构,它是动态地分配内存和动态增删的一种数据结构。与数组比起来

  • 数组需要连续的存储空间,而且大小固定(至少c是这样)不够灵活,但是优点就是访问速度快 。 (因为是连续的地址空间,访问第i个元素,逻辑地址 = sizeof(元素类型)*i);
  • 链表相对比较灵活,存储空间可以使离散的,大小可以动态扩充,增删等操作,但访问速度比较慢,因为需要整个链表地从头遍历,灵活带来的是维护代价。

c语言实现:


#include <stdio.h>
#include <stdlib.h>

/*功能:*/
/* 1.初始化线性表,输入n个数据 */
/* 2.打印链表,链表的遍历*/
/* 3.清除线性表L中的所有元素,即释放单链表L中所有的结点,使之成为一个空表 */
/* 4.返回单链表的长度 */
/* 5.检查单链表是否为空,若为空则返回1,否则返回0 */
/* 6.返回单链表中第pos个结点中的元素,若pos超出范围,则报错 */
/* 7.向单链表的表头插入一个元素 */
/* 8.向单链表的末尾添加一个元素 */
/* 9.向单链表中第pos个结点位置插入元素为x的结点 */
/* 10.从单链表中删除第pos个结点并返回它的值,若删除失败则报错,并返回原始链表 */


typedef struct node
{
  int number;
  struct node *next;
}List;

List *init()
{
    int n;
    List *head=NULL,*p,*p1;
    printf("输入一个整数表示链表长度\n");
    scanf("%d",&n);

    if(n>0)
    {
        p1=p=(List *)malloc(sizeof(List));
        if(p==NULL)
        {
            printf("内存申请失败!\n");
            return NULL;
        }
        head = p1;
        scanf("%d",&p1->number);
        p1->next = NULL;
        n=n-1;
        while(n>0)
        {
            n--;
            p=(List *)malloc(sizeof(List));
            if(p==NULL)
            {
            printf("内存申请失败!\n");
            return NULL;
            }
            scanf("%d",&p->number);
            p1->next = p;
            p1 = p;
        }
        p1->next = NULL;
    }
    return head;
}
//打印链表
void printList(List *phead)
{
    if(phead == NULL)
    {
        printf("该链表为空!\n");
    }else
    {
        while(phead!=NULL)
        {
            printf("%d ",phead->number);
            phead = phead->next;
        }
        printf("打印完成!\n");
    }
}

List * clearList(List *head)
{
    List *pt;
    while(head!=NULL)
    {
        pt = head->next;
        free(head);
        //head = NULL;
        head = pt;
    }
    printf("clear task funish!\n");
    return head;
}

int lengthList(List *head)
{
    int res=0;
    if(head==NULL)
    {
        res=0 ;
    }else
    {
        while(head!=NULL)
        {
            res++;
            head = head->next;
        }
    }
    return res;
}

int isEmptyList(List *head)
{
    if(head==NULL)
        return 1;
    else
        return 0;
}

int getValueList(List *head,int n)
{
    int res=0;
    if(n>lengthList(head))
    {
        printf("超出链表长度!\n");
    }else
    {
        while(n>0 && head!=NULL)
        {
            n--;
            res = head->number;
            head = head->next;
        }
    }
    return res;
}

List* insertHead(List *head,int value)
{
    List *p;
    p=(List *)malloc(sizeof(List));
    if(p==NULL) printf("申请内存失败!\n");
    else
    {
        p->number=value;
        p->next = head;
        head = p;
    }
    return head;
}

List *insertTail(List *head,int v)
{
    List *p,*pt;
    pt=head;
    p=(List *)malloc(sizeof(List));
    if(p==NULL) return head;
    p->number  = v;
    p->next=NULL;
    if(head==NULL)
    {
        head = p;
    }else
    {
        while(head->next!=NULL)
        {
            head=head->next;
        }
        head->next = p;
    }
    return pt;
}

List* insertList(List *head,int pos,int value)
{
    List *p,*pt,*p1;
    p1 = head;
    if(pos>lengthList(head)+1)
    {
        printf("超出链表范围!\n");
        return head;
    }else
    {
        p=(List*)malloc(sizeof(List));
        p->number = value;
        p->next = NULL;
        if(head==NULL && pos == 1)
        {
            p1=p;
        }else if(head != NULL && pos ==1)
        {
            p->next=head;
            p1=p;
        }else
        {
            while(pos>2)
            {
                pos--;
                head=head->next;
            }
            pt = head->next;
            head->next = p;
            p->next = pt;
        }

    }
    return p1;
}

List* deleteList(List *head,int pos)
{
    List *p,*p1,*p2;
    p2 = head;
    if(pos>lengthList(head) || pos<=0)
    {
        printf("删除位置不可用!\n");
        return head;
    }else
    {
        if(pos == 1) //第一位 特殊处理
        {
            p=head->next;
            free(head);
            head=p;
        }else
        {
            while(pos>1)
            {
                pos--;
                p1 = p2; //保留前一结点
                p2 = p2->next;
            }
            p1->next = p2->next; //跳过p2结点
            free(p2); //释放内存
        }
    }
    return head;
}

int main()
{
    //int length;
    List *Head=NULL;
    Head = init(); //初始化链表
    printList(Head); //打印链表
    //Head = clearList(Head);
    //length = lengthList(Head);
    //printf("%d",getValueList(Head,2));
    //Head = insertHead(Head,4);
    //Head = insertTail(Head,100);
    //Head = insertList(Head,2,50);
    Head = deleteList(Head,1);
    printList(Head);
    return 0;
}

小结:链表用c的结构体和指针实现比较容易。我在实现的清空链表的实现,遇到问题,因为Head->next 有时不为NULL,所以在遍历的时候瞬间爆炸,永远遍历不完0.0。
经过的我分析 原来是free()函数的问题。书上讲这个函数比较粗略。
我看了源码才明白:

void free(void *ptr) 
{

 struct mem_control_block *free;

 free = ptr - sizeof(struct mem_control_block);

 free->is_available = 1;

 return;
}

毕竟编译器不能执行释放内存这种事,他是操作系统该做的。所以呢,它只能告诉操作系统,这块内存地址又可以重新使用了。(free->is_available = 1;) 那操作系统用不用是它的事了,所以我们在使用free的时候要多加小心了。看下面的代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *p;
    int i=2333;
    p=(int*)malloc(sizeof(int));
    p=&i;
    printf("%d\n",*p); 
    free(p);
    printf("%d",*p);
    return 0; 
}

这段代码有80%的可能输出两个2333,但是还有可能致使程序崩溃0.0。
原因就是有20%的可能操作系统把这个地址用了不知道保存了什么东东。


                                       《完》
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值