单链表部分伪代码

链表部分伪代码

1、设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

文字思想;
	1)建立递归函数,每一轮进行判断L->data是否为x,是则进行删除结点操作,然后 L = L->next,直到遍历到链表尾部L->next = NULL
LNode *getElemByPos(LinkList L,int i) {
    int j = 1;
    LNode *P = L->next;
    if (i == 0) {
        return L;
    }
    if (i < 1) {
        return NULL;
    }
    while (P != NULL && j < i) {
        P = P->next;
        j++;
    }
    return P;
}

void delX(LinkList &L,ElemType x) {
    int i = 1;
    // 不带头结点
    if (L != NULL) {
        if (L->data == x) {
            LNode *P = getElemByPos(L,i-1);
            P->next = L->next;
        }
        i++;
        delX(L,x);
    } else {
        return ;
    }
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

参考答案:

文字思想:
	1)终止条件:表空
	2)划分为更小的问题:假设头指针为L
	如果表头元素为X,则删除X,子表为L->next,执行相同的操作
	如果表头元素不为X,子表为L->next,执行相同的操作
void delX(LinkList &L,ElemType x) {
    // 空表结束
	if (L == NULL) {
        return ;
    }
    // 数据域等于X的结点,执行删除
    if (L->data == x) {
        // 暂存X所在的结点
        LNode *P = L;
        // L指向X所在结点的下一个结点
        L = L->next;
        // 释放X所在结点
        free(P);
        // 递归处理子表
        delX(L,x);
    } else {
        // 第一个结点数据域不是x,则处理子表L->next
        delX(L->next,x);
    }
}

2、在带头结点的单链表L中,删除所有值为x的结点,并释放空间,假设值为x的结点不唯一,试编写算法以实现上述操作。

文字思想:
	和上题的区别就是带了头结点,且没有要求使用递归,所以可以用循环来替代尾递归,思路不变
void delX(LinkList &L,ElemType x) {
    // 跳过头结点
    L = L->next;
    int i = 1;
    // 只要结点不为空,就持续操作
    while (L != NULL) {
        if (L->data == x) {
            // 存储当前结点
            LNode *P = L;
            // 存储前驱结点
            LNode *Q = getElemByPos(L,i-1);
            // 使链表连续
            Q->next = P->next;
            L = L->next;
            free(P);
        }
        i++;
    }
}
LNode *getElemByPos(LinkList L,i) {
    if (i == 0) {
        return NULL;
    }
    if (i < 1) {
        return ;
    }
    int j = 1;
    while (L != NULL && j < i) {
        L = L->next;
        j++;
    }
    return L;
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

参考答案:

文字思想:
	1)将表L的头结点与其后序部分断开
	2)遍历后序部分,对于其值不等于x的结点,执行尾插到L的头结点后;对于其值等于x的结点,执行释放操作
void delXByTailInsert(LinkList L,ElemType x) {
    LNode *subHead = L->next;			// 摘下来的子表表头
    LNode *tailL = L;					// L表示的表的表尾
    LNode *aux;							// 工作指针
    while (subHead != NULL) {
        // 尾插到L代表的表尾
        if (subHead->data != x) {
            // 插入表尾,并更新表尾指针
            tailL->next = subHead;
            tailL = subHead;
            // 子表后移
            subHead = subHead->next;
            // 释放子表当前结点
        } else {
            // 暂存当前结点
            aux = subHead;
            // 子表表头后移
            subHead = subHead->next;
            // 释放
            free(aux);
        }
    }
    // L代表的表的尾结点的next设置为NULL
    tailL->next = NULL;
}

时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1)

3、设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

文字思想:
	1)实现从头到尾反向输出,可想到单链表的"头插法"
	2)注意L是带头结点的单链表
bool LinkReverse(LinkList &L) {
    if (L == NULL) {
  		return false;
    }
    // 跳过头结点
   	LNode *subHead = L->next;
    L->next = NULL;
    while (subHead != NULL) {
        // aux存储当前结点
        LNode *aux = subHead;
        // 子表结点后移
        subHead = subHead->next;
        // 将当前结点头插到L中
        aux->next = L->next;
        L->next = aux;
       	free(aux);
    }
    return true;
}

时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1)

4、编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点是唯一的)

文字思想:
	1)遍历整个单链表,创建指针变量接收当前结点及其前驱结点,找到比它值小的就更新指针指向当前结点
	2)整个循环下来,指针指向的就是最小值结点
void delMinNode(LinkList &L) {
    // 存储头结点
    LNode *subHead = L;
    L = L->next;
    ElemType min = L->data;
    // 存储最小值结点的前驱结点
    LNode *aux;
    // 直到表空才退出循环
    while (subHead != NULL) {
        // 遇到比min小的就更新min值,并记下前驱结点
        if (min > subHead->next->data) {
            min = subHead->next->data;
            aux = subHead;
        }
        // 指向下一个结点
        subHead = subHead->next;
    }
    // 最后的aux指向的就是最小值结点的前驱结点
    LNode *Z = aux->next;
    aux->next = Z->next;
    free(Z);
}

时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1)

5、试编写算法将带头结点的单链表就地逆置,所谓"就地"是指辅助空间复杂度为 O ( 1 ) O(1) O(1)

文字思想:
	1)要求存储单链表数据反序,可以考虑使用单链表的头插法
void LinkReverse(LinkList &L) {
    // 存储头结点后面结点
    LNode *subHead = L->next;
    // 作为头结点存在
    L->next = NULL;
    LNode *aux;
    while (subHead != NULL) {
        // 存储当前结点
        aux = subHead;
        subHead = subHead->next;
        L->next = aux;
    }
}

时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( 1 ) O(1) O(1)

6、有一个带头结点的单链表L,设计一个算法使其元素递增有序

文字思想:
	1)使用数组存储L中各个元素的值,然后进行排序
	2)设置LNode *subHead = L,L->next = NULL,则L保存的是原先的头结点,则利用头插法可以将数组中的元素依次插入到L后,则将有序表全部插完后整个L存储的结点元素值便是递增有序的
void LinkSort(LinkList L) {
    LNode *subHead = L;
    // 存储头结点,对有序表进行头插法
    L->next = NULL;
    // 计算结点的个数,方便使用数组存储
    int count = 0;
    while (subHead != NULL) {
        count += 1;
        L->next = subHead;
        subHead = subHead->next;
    }
    int *temp = (int *)malloc(sizeof(int) * count);
    memset(temp,0,sizeof(int)*count);
    subHead = L;
    L->next = NULL;
    int i;
    for (i = 0;i < count;i++) {
        temp[i] = subHead->data;
        subHead = subHead->next;
    }
    // 进行选择排序,每一轮选择最大的元素,直到表为空
    int j = 0,min;
    while (j < count) {
        min = temp[j];
        for (j = 0;j < count;j++) {
            if (min > temp[j]) {
                min = temp[j];
            }
        }
        // 使用头插法插入到L后
        LNode *r;
        r->data = min;
        r->next = L->next;
        L->next = r;
    }
    L->next = NULL;
}

时间复杂度: O ( n 2 ) O(n^2) O(n2) 空间复杂度: O ( n ) O(n) O(n)

参考答案:

文字思想:
	1)待排序列L[1…n]某时状态如此:有序序列L[1,…i-1],L[i],无序序列L[i+1…n]
	2)将L[i]插入到已有序的子序列L[1…i-1]中
// 使用直接插入排序算法进行排序
void insertSort(LinkList L) {
    LNode *curp = L->next,				// 第一个元素结点
    	  *prep,
    	  // 用于标识无序部分链表
    	  // 第一个元素结点认为是有序的,无序部分从第二个开始
    	  *subL = curp->next;			
    // 刚开始,有序部分只有一个元素,最后一个元素的next应该是NULL
    curp->next = NULL;
    // 从第二个元素结点开始处理【无序部分】
    curp = subL;
    // 无序部分还有结点的时候
    while (curp != NULL) {
        // curp将会插入到有序部分,所以先保存它的后继【新的无序部分】
        subL = curp->next;
        // 准备从前向后找第一个大于curp元素的前一个结点
        prep = L;
        while (prep->next != NULL && prep->next->data < curp->data) {
            // 当前元素最后一位仍然小于curp
            // 有序部分后移
            prep = prep->next;
        }
        // 退出时,prep后面就是curp的插入位置
        /*
        	1、curp是最大的
        	2、prep->next是第一个大于curp的结点
        */
        // 典型的插入操作【待插入的结点主动】
        curp->next = prep->next;
        prep->next = curp;
        // 处理无序部分的下一个结点
        curp = subL;
    }
}

时间复杂度: O ( n 2 ) O(n^2) O(n2) 空间复杂度: O ( 1 ) O(1) O(1)

7、设在一个带表头结点的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素的元素(若存在)

文字思想:
	1)设置前驱结点指针和当前结点指针,在遍历到合适的结点满足数据值在给定范围内时,通过前驱结点指针删除当前结点,并连接到当前结点的后继结点
void delRange(LinkList L,int start,int end) {
    LNode *aux = L,*subHead = L->next;
    while (subHead != NULL) {
        if (subHead->data >= start && subHead->data <= end) {
            // 存储当前结点
            LNode *P = subHead;
            aux->next = P->next;
            free(P);
        } else {
            // 指向后一结点
        	aux = subHead;
        	subHead = subHead->next;
        }
    }
}

8、给定两个链表,编写算法找出两个链表的公共结点

文字思想:
	1)公共结点就是地址(指针)相同
	2)问题转化为遍历链表A和B,找到地址值相同的第一个结点
LNode *findFirstNode(LinkList A,LinkList B) {
    // 假设都是带头结点的链表
    LNode *subHead = A->next;
    A->next = NULL;
    // A链表中结点逐个比较B中结点情况
    while (subHead != NULL) {
        LNode *head = B->next;
        B->next = NULL;
        while (head != NULL) {
            // 若找到两个地
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值