哈佛大学公开课:计算机科学cs50 学习笔记(第12集:单链表,内存分配)

1. 数组的优缺点

数组元素是连续的存储在有限的内存里,这样有两个缺点:

--数组的大小是有限的。如果需要给数组的内存(缓冲区buffer)扩容,需要调用realloc()函数。realloc()的工作原理:在内部调用malloc()来分配一块新的内存,然后用循环将原先内存的内容拷贝到新内存,然后free()掉原来的内存,返回新内存的地址。

--不方便进行元素的插入与删除。因为元素连续存储,互相之间没有空余的内存。

当然数组也有一个优点:不需要多余的信息就可以依次遍历,因为元素在内存中连续分布。

2. 单链表

单链表是这样一种结构:

 

它在内存中分散存储,用指针来依次关联。

链表的每个节点都是一个结构体struct,至少包含两个元素。例如:

typedef struct node
{
    int n;
    struct node * next;
} node;

链表的每个节点(除首末节点外)都用一个指针指向下一个元素,无序,因此链表不能使用二分法来查找。只能遍历。

 

链表节点的插入与删除 比数组容易多了,因为数组元素连续存储,元素互相之间没有空余的内存。

插入与删除分为三类:

首元素,

中间元素,

尾元素

 

代码一点点补上。

--------------------------------------------

下面的代码其实用的是C,但是因为.c文件不支持指针的引用,所以就用了.cpp

Slist.cpp

#include "Slist.h"

//建立节点
SListNode* 
_buildNode(DataType x)    
{
    SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
    tmp->data = x;
    tmp->next = NULL;
 
    return tmp;
}

// 打印单链表
void 
printSlist(SListNode* headNode)   
{
    SListNode* curNode = headNode;
    while (curNode)
    {
        printf("%d->", curNode->data);
        curNode = curNode->next;
    }
 
    printf("NULL\n");
}


//尾插
void 
pushBack(SListNode* & headNode, DataType x)  
{
    // 1.空
    // 2.不为空
    if (headNode == NULL)
    {
        headNode = _buildNode(x);
    }
    else
    {
        // 找尾
        SListNode* tail = headNode;
        while (tail->next != NULL)
        {
            tail = tail->next;
        }
 
        tail->next = _buildNode(x);
    }
}

//  尾删
void 
popBack(SListNode* & headNode)     
{
    //
    // 1.空
    // 2.一个节点
    // 3.多个节点
    //
    if (headNode == NULL)
    {
        return;
    }
    else if (headNode->next == NULL)
    {
        free(headNode);
        headNode = NULL;
    }
    else
    {
        // 找尾
        SListNode* tail = headNode;
        SListNode* prev = NULL;
        while (tail->next)
        {
            prev = tail;
            tail = tail->next;
        }
 
        free(tail);
        prev->next = NULL;
    }
}


//头插
void 
pushFront(SListNode* & headNode, DataType x)   
{
    // 1.空
    // 2.不空
    if (headNode == NULL)
    {
        headNode = _buildNode(x);
    }
    else
    {
        SListNode* tmp = _buildNode(x);
        tmp->next = headNode;
        headNode = tmp;
    }
}


//头删
void 
popFront(SListNode* & headNode)   
{
    //
    // 1.空
    // 2.一个节点
    // 3.一个以上的节点
    //
    if (headNode == NULL)
    {
        return;
    }
    else if (headNode->next == NULL)
    {
        free(headNode);
        headNode = NULL;
    }
    else
    {
        SListNode* tmp = headNode;
        headNode = headNode->next;
        // free 掉 tmp 指针指向的内存
        free(tmp);
    }
}


// 插入中间节点
void 
insertNode(SListNode* pos, DataType x)   
{
    assert(pos);
 
    SListNode* tmp = _buildNode(x);
    tmp->next = pos->next;
    pos->next = tmp;
}


// 删除中间的节点
void 
deleteNode(SListNode*& headNode, SListNode* pos)   
{
    assert(pos);
    assert(headNode);
 
    //pos为头结点
    if (headNode == pos)
    {
        headNode = headNode->next;
        // free 掉 tmp 指针指向的内存
        free(pos);
        return;
    }
    
    SListNode* prev = headNode;
    while (prev)
    {
        if (prev->next == pos)
        {
            prev->next = pos->next;
            free(pos);
            break;
        }
        prev = prev->next;
    }
}

可见,链表需要指针来找到下一个节点,此外,链表每插入一个元素都要malloc,这样做的缺点是,效率低因为内存分配以及内存中内容的拷贝很占用CPU周期

 

Slist.h

#ifndef SLIST_H
#define SLIST_H


#include<stdio.h>
#include<assert.h>
#include<malloc.h>

typedef int DataType;

struct SListNode
{
    DataType data;            // 数据
    struct SListNode* next;   //指向下一个节点的指针
};


//建立节点
SListNode* 
_buildNode(DataType x);


// 打印单链表
void 
printSlist(SListNode* headNode);


//尾插
void 
pushBack(SListNode * & headNode, DataType x);


//  尾删
void 
popBack(SListNode * & headNode);


//头插
void 
pushFront(SListNode * & headNode, DataType x);



//头删
void 
popFront(SListNode * & headNode);


// 插入中间节点
void 
insertNode(SListNode * pos, DataType x);


// 删除中间的节点
void 
deleteNode(SListNode * & headNode, SListNode* pos);



#endif

 

main.cpp

#include "Slist.h"

int
main(int argc, char const *argv[])
{
    SListNode * headNode = NULL;
    for(DataType i = 0; i != 10; ++i)
    {
        pushBack(headNode, i);
        printSlist(headNode);
    }
    for(DataType i = 10; i != 20; ++i)
    {
        pushFront(headNode, i);
        printSlist(headNode);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值