线性表的链式存储实现(C语言)

 

上一篇用数组实现了线性表的存储,但是这种方式在插入和删除元素时,需要通过元素的移动来实现,效率比较低。而且在估计的最大数组个数小于实际情况时,不好处理。我们可以通过链式存储来实现,是通过“链”来连接元素,因此对于线性表的插入和删除只需要对链进行操作即可。

我们将链表中的一个节点表示为如下(每个节点都包含一个指向下一个节点的指针):

typedef int ElementType; //定义元素类型
typedef struct LNode * pToLnode; //定义一个结构体指针
struct LNode {
    ElementType Data; //表示当前节点存储的元素
    pToLnode    next; //指向下一个节点
};

我们用List来表示这个链表的表头节点指针:

typedef pToLnode List;
//List L; 代表了一个链表
typedef pToLnode Position; //表示指向某个节点的指针

下面来看一下这个链表的相关操作:

链表的长度:

如果是数组方式的线性表,可以直接返回last+1表示长度,但是在链式表中,只能通过遍历链表实现查询长度。

int getLength(List L){  //求表长
    Position p = L;
    int length = 0;
    while(p){
        p = p->next;
        length++;
    }
    return length;
}

按序号查找:

ElementType FindWithIndex(List L,int index){ //按下标查找
    Position p = L;
    int len = 1;
    while(p && len < index){//遍历链表 当遍历结束 或 len==下标时跳出
        p = p->next;
        len++;
    }
    if (len == index && p) return p->Data;//返回找到的元素
    else return -1; //返回-1表示该位置不存在
}

按值查找:

Position FindWithValue(List L,ElementType x){//按值查找
    Position p = L;
    int len = 1;
    while(p && p->Data != x){//遍历链表 直到  遍历结束 或 找到值
        p = p->next;
        len++;
    }
    if (p->Data == x && p) return p;
    else return NULL; //返回null表示查找失败
}

插入元素到表中:

List insertList(List L, ElementType x, int n){//插表
    Position temp, pre;
    temp = (Position)malloc(sizeof(struct LNode));
    temp->Data = x;
    if (x == 1){ //插到表头
        temp->next = L; //插到表头的时候需要对L重新赋值L = insert(...) 因为表头位置已经改变
        return temp;
    }else{
        int len = 0;
        pre = L;
        while(pre && lennext;
            len++;
        }
        if (pre == NULL && len != n){
            printf("没有该位置\n");
            free(temp);
            return NULL;
        }else{
            temp->next = pre->next;
            pre->next = temp;
            return L;
        }
    }
}

这样的情况下,需要区分是否插入到表头的情况。而且这种方式,接口也和之前的不一样了。我们还可以改进一下,为链表增加一个空的“表头节点”,真正的第一个表头元素在这个节点之后,这样处理表头就和处理其他位置的元素一样了,表头节点永远指向一个固定的位置。

//假设链表已经有了一个头结点
bool insertList1(List L,ElementType x, int n){//带头结点的表的插入
    Position pre,temp;
    pre = L;
    int len=0;
    while(pre && lennext;
        len++;
    }
    if (pre == NULL || len != n){
        printf("位置错误\n");
        return false;
    }else{
        temp = (Position)malloc(sizeof(struct LNode));
        temp->Data = x;
        temp->next = pre->next;
        pre->next  = temp;
        return true;
    }

}

链表元素的删除:

bool deleteList(List L, int index){ //带头结点的链表的删除
    Position pre, temp;
    pre = L;
    int len = 0;
    while(pre && lennext;
        len++;
    }
    if (pre == NULL || len != index-1 || pre->next == NULL){
        printf("位置错误\n");
        return false;
    }else{
        temp = pre->next;
        pre->next = temp->next;
        free(temp);
        return true;
    }


}

总结:

1.在单链表上插入、删除一个节点时,需要知道这个节点之前的一个节点(前驱节点);

2.单链表不能直接通过需要访问,只能从头指针一个一个按顺序访问;

你可能感兴趣的:(数据结构与算法)