C语言链表实现

链表实现的逻辑

链表,本质是结构体,包含了节点值和后节点指针两个数据(双向链表会有两个节点指针)

struct LIST{
    int data;
    struct LIST* next;
};
//创建了struct LIST结构体

基本操作的代码实现

插入
struct LIST* listInsert(struct LIST *head,int data,int n){//在索引为i的节点插入新节点(初始索引为0)
    struct LIST *temp1=(struct LIST*)malloc(sizeof(struct LIST));//创建新节点
    temp1->data=data;
    temp1->next=NULL;
    if(n==0){//头插入
        temp1->next=head;
        head=temp1;
        return head;
    }
    struct LIST *temp2=head;//遍历到目标节点的前节点
    for(int i=0;i<n-1;i++){
        temp2=temp2->next;
    }
    temp1->next=temp2->next;//新节点指向目标节点
    temp2->next=temp1;//前节点指向新节点
    return head;//更新头节点
}

优化:

int listLength(struct ListNode* head){
    int len=0;
    struct ListNode *temp=head->next;
    while(temp){
        ++len;
        temp=temp->next;
    }
    return len;
}
int addAtIndex(struct ListNode* head, int index, int val){
    int len=listLength(head);//得到链表长度
    if(index>len || index<0){//判断是否超范围
        return 0;
    }
    else{//范围合理
        struct ListNode *prev=head;
        struct ListNode *newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
        newnode->val=val;
        for(int i=0;i<index;i++){
            prev=prev->next;
        }
        newnode->next=prev->next;
        prev->next=newnode;
        return 1;
    }
    return 0;
}
//head->next为头节点
//成功插入返回1,否则返回0
删除
struct LIST* listDelete(struct LIST *head,int target){//删除节点值为target的节点
    if(target==head->data){//只有一个节点
        head=NULL;
        return head;
    }
    struct LIST *temp1=head;
    while((temp1->next)->data!=target){
        temp1=temp1->next;//遍历到目标节点的前节点
    }
    struct LIST *temp2=temp1->next;//temp2为目标节点
    temp1->next=temp2->next;
    temp2->next=NULL;
    return head;
}
打印
void printList(struct LIST *head){//打印链表
    struct LIST *temp=head;
    printf("list is:");
    while(temp!=NULL){//遍历所有节点并打印
        printf("%d ",temp->data);
        temp=temp->next;
    }
    printf("\n");
}
释放空间
void listFree(struct LIST *head){//释放空间
    if(head){
        //递归free空间
        struct LIST *temp=head->next;
        free(head);
        listFree(temp);
    }
}
求长度
int listLength_fir(struct LIST *head){//得到链表长度
    if(head) return listLength(head->next)+1;
    else return 0;
}

int listLength_sec(struct ListNode* head){
    int len=0;
    struct ListNode *temp=head->next;
    while(temp){
        ++len;
        temp=temp->next;
    }
    return len;
}
寻找节点
struct LIST* listFind(struct LIST *head,int target){//找到data为target的节点
    struct LIST *temp=head;
    while(temp->data!=target){
        temp=temp->next;//未找到,不断后移节点
    }
    return temp;   
}
反转链表
struct LIST* listReverse(struct LIST *head){//反转链表
    if(!head->next){//一个节点
        return head;
    }
    else if(!(head->next)->next){//两个节点
        (head->next)->next=head;
        head->next=NULL;
        return head;
    }
    struct LIST* temp1=head;//前节点
    struct LIST* temp2=head->next;//中间节点
    struct LIST* temp3=temp2->next;//后节点
    while(temp3!=NULL){//中节点为最后有效节点
        temp2->next=temp1;//中节点指向前节点
        temp1=temp2;//前节点后移
        temp2=temp3;//中节点后移
        temp3=temp3->next;//后节点但后移
    }
    temp2->next=temp1;//最后有效节点处理
    head->next=NULL;//头节点指向NULL
    head=temp2;//头节点变换为尾节点
    return head;//返回新的头节点
}

易错点

每次操作完,必须更新头节点,因为头节点指向内容虽然改变,但是头节点本身地址并没有改变,

除非使用

struct LIST **head_ref;
//创建头节点指针的指针

这样就不需要显式地更新头节点

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表实现二叉树是一种常见的数据结构,可以用于存储和操作树形结构的数据。下面是C语言链表实现二叉树的方法: 定义结构体: ```c typedef struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; } TreeNode; ``` 初始化: ```c TreeNode *root = NULL; ``` 先序遍历创建二叉树方法一: ```c void createTree(TreeNode **node) { int data; scanf("%d", &data); if (data == -1) { *node = NULL; } else { *node = (TreeNode *)malloc(sizeof(TreeNode)); (*node)->data = data; createTree(&((*node)->left)); createTree(&((*node)->right))); } } ``` 测试: ```c int main() { createTree(&root); return 0; } ``` 方法二:根据所给的字符串序列创建 ```c void createTree(TreeNode **node, char *str, int *index) { if (str[*index] == '\0' || str[*index] == '#') { *node = NULL; (*index)++; } else { *node = (TreeNode *)malloc(sizeof(TreeNode)); (*node)->data = str[*index] - '0'; (*index)++; createTree(&((*node)->left), str, index); createTree(&((*node)->right), str, index); } } ``` 其他方法: - 树的结点大小 ```c int size(TreeNode *node) { if (node == NULL) { return 0; } else { return size(node->left) + 1 + size(node->right); } } ``` - 树的高 ```c int height(TreeNode *node) { if (node == NULL) { return 0; } else { int leftHeight = height(node->left); int rightHeight = height(node->right); return (leftHeight > rightHeight) ? (leftHeight + 1) : (rightHeight + 1); } } ``` - 判断树是否为空 ```c int isEmpty(TreeNode *node) { return node == NULL; } ``` - 找某个结点的左孩子和右孩子 ```c TreeNode *leftChild(TreeNode *node) { if (node == NULL) { return NULL; } else { return node->left; } } TreeNode *rightChild(TreeNode *node) { if (node == NULL) { return NULL; } else { return node->right; } } ``` - 找某个结点的父节点 ```c TreeNode *parent(TreeNode *root, TreeNode *node) { if (root == NULL || root == node) { return NULL; } else if (root->left == node || root->right == node) { return root; } else { TreeNode *p = parent(root->left, node); if (p != NULL) { return p; } else { return parent(root->right, node); } } } ``` - 查找元素 ```c TreeNode *find(TreeNode *node, int data) { if (node == NULL) { return NULL; } else if (node->data == data) { return node; } else { TreeNode *p = find(node->left, data); if (p != NULL) { return p; } else { return find(node->right, data); } } } ``` - 拷贝树 ```c TreeNode *copy(TreeNode *node) { if (node == NULL) { return NULL; } else { TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode)); newNode->data = node->data; newNode->left = copy(node->left); newNode->right = copy(node->right); return newNode; } } ``` - 清空树 ```c void clear(TreeNode **node) { if (*node != NULL) { clear(&((*node)->left)); clear(&((*node)->right)); free(*node); *node = NULL; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值