【数据结构】之链表操作

简介

       单链表:每个节点只有一个指向后一个节点的指针。

      循环链表:最后一个节点的指针指向该循环链表的第一个节点或者表头节点

      双向链表:节点除了含有数据域外,还有两个指针,一个指向后继节点,一个指向前驱节点。

双向循环链表:将双向链表首尾相连。

【 链表插入顺序补充说明】:

单链表插入顺序:

/* 节点p的后面插入指针s */
s->next = p->next;    //先解决插入节点的后继
p->next = s;          //再解决前节点的后继

双向循环链表插入顺序:

/* p节点后面插入新节点s */
s->left = p;               //先解决新插入节点的前驱和后继
s->right = p->right;
p->right->left = s;        //再解决后节点的前驱
p->right = s               //最后解决前节点的后继

一、单链表操作

1.1 定义单链表节点

typedef struct node{
    int data;    //数据域
    node *next;    //指向下一个节点
}node;

1.2 创建单链表

/* 创建带头单链表 */
node *list_create()
{
    int i = 0;
    node *head, *cur, *tail;
    int x = 0;
    head = (node *)malloc(sizeof(node));     // 创建头节点

    while(1){
        scanf("%d", &x);                     // 输入节点数据
        
        cur = (node *)malloc(sizeof(node));
        cur->data = x;
        if(++i == 1){                        //链表只有一个元素
            head->next = cur;                  //连接到head后面
        }esle{
            tail->next = cur;                  //连接到链表尾端
        }
        tail = cur;                            //tail指向末节点
    }
    tail->next = NULL;                        //链表的最后一个指针为空
    return head;
}

1.3 获取链表的长度

/* 获取链表长度 */
int list_length(node *head)
{
    int len = 0;
    node *cur;
    cur = head->next;
    while(cur != NULL){
        len++;
        cur = cur->next;
    }
    
    return len;
}

1.4 单链表打印

/* 单链表打印 */
void list_show(node *head)
{
    node *cur;
    int index = 0;
    if(head->next == NULL){
        printf("List is empty!");
        return;
    }

    cur = head->next;
    while(cur != NULL){
        printf("The %dth node data is: %d\n", ++index, cur->data);
        cur = cur->next;
    }
}

1.5 单链表节点查找

/* 
* 通过位置查找节点,返回节点指针 
* 位置0返回head节点
*/
node *list_search_node(node *head, int pos)
{
    node *p = head->next;
    if(pos < 0){
        return NULL;
    }

    if(pos == 0){
        return head;
    }

    if(p == NULL){        //链表为空
        return NULL
    }

    while(--pos){
        if((p = p->next) == NULL){
            break;
        }
    }

    return p;
}

1.6 单链表节点插入

node *list_insert_node(node *head, int pos, int data)
{
    node *item = NULL;
    node *p;
    
    item = (node *)malloc(sizeof(node));
    item->data = data;
    if(pos == 0){
        head->next = item;
        return head;
    }

    p = list_search_node(head, pos);    
    if(p != NULL){
        item->next = p->next;
        p->next = item;
    }
    return head;
}

1.7 单链表节点删除

node *list_delete_node(node *head, int pos)
{
    node *item = NULL;
    node *p = head->next;
    if(p == NULL){
        return NULL;
    }

    p = list_search_node(head, pos - 1);
    if(p != NULL && p->next != NULL){
        item = p->next ;
        p->next = item->next;
        p->next = item->next;
        free(item);
        item = NULL;
    }
    
    return head;
}

1.8 单链表逆序

node *list_reverse(node *head)
{
    node *p, *q, *r;
    if(head->next == NULL){
        return head;
    }

    p = head->next;
    q = p->next;    //保存第二个节点

    p->next = NULL;    //原第一个节点翻转

    while(q != NULL){
        r = q->next;        //保存当前下一个节点
        q-next = p;         //指针方向翻转
        p = q;             //p指针右移
        q = r;             //q指针右移
    }

    head->next = p;        //头节点指向原来末尾的节点
    return head;
}

1.9 单链表找中间元素

node *list_search_middle(node *head)
{
    int i = 0;
    int j = 0;
    node *cur = NULL;
    node *mid = NULL;
    
    cur = mid = head->next;
    while(cur != NULL){
        if(i/2 > j){
            j++;
            mid = mid->next;
        }
        i++;
        cur = cur->next;
    }

    return mid;
}

 1.10 单链表正排序

node *list_insertSort(void)
{
    int data = 0;
    node *head = NULL, *new, *cur, *pre;
    while(1){
        scanf("%d", &data);
        new = (node *)malloc(sizeof(node));
        new->data = data;
        new->next = NULL;
        if(head == NULL){
            head = new;
            continue;
        }
        
        if(new->data <= head->data){
            new->next = head;         //head之前插入节点       
            head = new;
            continue;
        }
        cur = head;
        while(new->data > cur->data && cur->next != NULL){  //找到插入位置
            pre = cur;
            cur = cur->next;
        }
        if(cur->data >= new->data){
            pre->next = new;          //new插入到pre和cur之间      
            new->next = cur;
        }
        else
            cur->next = new;           //new插入cur之后
    
    }
    return head;
}

1.11 判断链表是否为环形

方法:两个指针,一个指针偏移个节点,另一个偏移2个节点。

bool list_isLoop(node *head, node **start)
{
    node *p1 = head, *p2 = head;
    if(head == NULL || head->next == NULL){
        return false;
    }
    do{
        p1 = p1->next;
        p2 = p2->next-next;
    }while(p2 && p2->next && p1 = p2);

    if(p1 == p2){
        *start = p1;
        return ture;
    }
    else
        return false;
}

1.12 有序单链表合并

node *list_insert_node(node *head, node *item)
{
    node *p = head;
    node *q = NULL;

    while(p->data < item->data && p != NULL){
        q = p;
        p = p->next;
    }
    if(p == head){
        item->next = p;
        return item;
    }

    q->next = item;
    item->next = p;
    return head;
}

/* 两个有序链表合并 */
node *list_merge(node *head1, node *head2)
{
    node *head;
    node *p ;
    node *p_next;

    if(head1 == NULL){
        return head2;
    }else if(head2 == NULL){
        return head1;
    }

    if(list_length(head1) >= list_length(head2)){
        head = head1;
        p = head2;
    }else{
        head = head2;
        p = head1;
    }

    while(p != NULL){
        p_next = p->next;
        head = list_insert_node(head, p);
        p = p_next
    }

    return head;
}

二、双向链表

  定义双向链表节点:

typedef struct DNODE{
    int data;
    dnode *left;        //前驱
    dnode *right;       //后继
}dnode;

2.1 创建双向链表

/* 创建新节点 */
dnode * dlist_create_node(int data)
{
    dnode *p = (dnode *)malloc(sizeof(dnode));
    p->data = data;
    p->left = p->right = p;        //创建新节点时让前驱和后继都指向自身

    return p;
}

/* 创建头节点 */
dnode *dlist_create_node(int head)
{
    dnode *p = (dnode *)malloc(sizeof(dnode));
    p->data = head;
    p->left = p->right = p;        //创建新节点时让前驱和后继都指向自身

    return p;
}

/* 创建双链表 */
dnode *dlist_create(dnode *head, int data)
{
    dnode *new = dlist_create_node(data);
    dnode *p = head ,*q;
    
    while(p != NULL){
        q = p;
        p = p->right;
    }
    q->right = new;
    new->left = q;
    
    return head;   
}

2.2 双向链表打印

void dlist_show(dnode *head)
{
    dnode *p = NULL;
    if(head == NULL){
        return ;
    }
    p = head;
    while(p != NULL){
        printf("%d ", p->data);
        p = p->right;
    }
    printf("\n");
}

2.3 双链表查找

dnode *dlist_search_node(dnode *head, int data)
{
    dnode *p = head;
    if(head == NULL)
        return NULL;
    
    while(p->right != NULL && p->data != data){
        p = p->right;
    }

    if(p->right == NULL)
        return NULL;
    
    return p;
}

2.4 双向链表插入

void dlist_insert_node(dnode *node, int data)
{
    dnode *new = dlist_create_node(data);
    dnode *p = NULL;
     
    if(node == NULL)
        return NULL;
    if(node->right == NULL){
        node->right = new;
        new->left = node;
    }else{
        new->right = node->right;    //先连new的后继
        node->right->left = new;    //后节点的前驱指向new
        node->right = new;            //前节点指向new
        new->left = node;            //new的前驱
    }
}

2.5 双链表删除节点

dnode *dlist_deletenode(dnode *head, int data)
{
    dnode *tmp = NULL;
    dnode *p = dlist_search_node(head, data);
    if(p == NULL){
           return NULL;
    }else if(p->left == NULL){        //第一个节点
        head = p->right;
        if(head != NULL)
            head->left = NULL;
    }else if(p->right == NULL){        //最后节点
        p->left->right = NULL;
    }else{                             
        p->left->right = p->right;
        p->right->left = p->left;
    }

    free(p);
    p = NULL;
    return head;
    
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值