c语言有序链表合并,我找不到问题所在,求纠错!!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言有序链表合并,我找不到问题所在,求纠错!!相关的知识,希望对你有一定的参考价值。

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include<conio.h>

#define OK 1;
#define ERROR 0;

typedef int Status;
typedef int ElemType;

typedef struct LNode
ElemType data;
struct LNode *next;
*Link;

typedef struct
Link head, tail;
int len;
LinkList;

Status ListInsert_front_L(LinkList &L, ElemType e)

Link q;
q = (Link)malloc(sizeof(LNode));
if(!q)
return ERROR;
q->data = e;
q->next = L.head->next;
L.head->next = q;
L.len++;
if(!L.tail)
L.tail = q;
return OK;


void ListTraverse_L(LinkList &L)

Link p;
int i;
if(L.len == 0)
printf("空表\n");
else

int i = 1;
p = L.head->next;
while(i<=L.len)

printf("%d ",p->data);
i++;
p = p->next;




Status ListCreat_L(LinkList &L)

L.head = (Link)malloc(sizeof(LNode));
L.tail = NULL;
L.len = 0;
int i, temp;
i = rand();
temp = i - 5;
for(i; i > temp; i --)

ListInsert_front_L(L, i);

return OK;


void Union(LinkList a, LinkList b, LinkList &c)

Link ap, bp, cp, tp;
c.head = (Link)malloc(sizeof(LNode));
c.len = 0;
c.tail = NULL;
cp = (Link)malloc(sizeof(LNode));
ap = a.head->next;
bp = b.head->next;
cp = c.head->next;
while(ap || bp)

if(ap<bp)

cp = ap;
ap = ap->next;

else if(ap>=bp)

cp = bp;
bp = bp->next;

tp = (Link)malloc(sizeof(LNode));
tp = cp->next;
cp = tp;
c.len++;

free(cp);

int main()

LinkList A, B, C;
ListCreat_L(A);
ListCreat_L(B);
printf("随机生成线性表A:");
ListTraverse_L(A);
printf("\n随机生成线性表B:");
ListTraverse_L(B);
Union(A, B, C);
printf("\nA、B表的交集线性表C:");
ListTraverse_L(C);
system("PAUSE");
return 0;

参考技术A 不晓得 参考技术B 从Union里的这句入手
bp = bp->next;
参考技术C #include <stdio.h>
#include <stdlib.h>
#include<conio.h>

#define OK 1;
#define ERROR 0;

typedef int Status;
typedef int ElemType;

typedef struct LNode
ElemType data;
struct LNode *next;
*Link;

typedef struct
Link head, tail;
int len;
LinkList;

Status ListInsert_front_L(LinkList &L, ElemType e)

Link q;
q = (Link)malloc(sizeof(LNode));
if(!q)
return ERROR;
q->data = e;
q->next = L.head->next;
L.head->next = q;
L.len++;
if(!L.tail)
L.tail = q;
return OK;


void ListTraverse_L(LinkList &L)

Link p;
int i;
if(L.len == 0)
printf("空表\n");
else

int i = 1;
p = L.head->next;
while(i<=L.len)

printf("%d ",p->data);
i++;
p = p->next;




Status ListCreat_L(LinkList &L)

L.head = (Link)malloc(sizeof(LNode));
L.tail = NULL;
L.head->next=NULL;
L.len = 0;
int i, temp;
i = rand();
temp = i - 5;
for(; i > temp; i --)

ListInsert_front_L(L, i);

return OK;


LinkList Union(LinkList a, LinkList b)

LinkList c;
Link ap, bp, cp, tp;
c.head = (Link)malloc(sizeof(LNode));
c.len = 0;
c.head->next=NULL;
c.tail = NULL;
//cp = (Link)malloc(sizeof(LNode));
//ap = a.head->next;
//bp = b.head->next;
//cp = c.head->next;
while(a.head!=NULL&& b.head!=NULL)

if(a.head->data<b.head->data)

// cp = ap;
// ap = ap->next;
c.head->next=a.head;
c.head=a.head;
a.head->next=a.head->next->next;


else

//cp = bp;
//bp = bp->next;
c.head->next=b.head;
c.head=b.head;
b.head->next=b.head->next->next;

//tp = (Link)malloc(sizeof(LNode));
//tp = cp->next;
//cp = tp;
c.len++;

//free(cp);
if(a.head!=NULL)
c.head->next=a.head;
else
c.head->next=b.head;
return c;

int main()

LinkList A, B, C;
ListCreat_L(A);
ListCreat_L(B);
printf("随机生成线性表A:");
ListTraverse_L(A);
printf("\n随机生成线性表B:");
ListTraverse_L(B);
C=Union(A, B);
printf("\nA、B表的交集线性表C:");
ListTraverse_L(C);
system("PAUSE");
return 0;

我修改了一下.源程序有点乱.双向的线性链表....追问

谢谢~不过还是有错额

参考技术D 调试成功!但由于原程序错误太多,主要是类C和C的区别造成的,因此没注释过多,哪有问题再问吧
#pragma once

#include <stdio.h>
#include <stdlib.h>
#include<conio.h>
#include<malloc.h>

#define OK 1;
#define ERROR 0;

typedef int Status;
typedef int ElemType;

typedef struct LNode
ElemType data;
struct LNode *next;
Link;

typedef struct
Link *head, *tail;
int len;
LinkList;

Status ListInsert_front_L(LinkList *L, ElemType e)

Link *q;
q=(Link*)malloc(sizeof(Link));
if(!q)
return ERROR;
q->data = e;
q->next = L->head->next;
L->head->next = q;
L->len++;
if(!L->tail)
L->tail = q;
return OK;


void ListTraverse_L(LinkList *L)

Link *p;
if(L->len == 0)
printf("空表\n");
else

p = L->head->next;
while(p)

printf("%d ",p->data);
p = p->next;
printf("\n");



Status ListCreat_L(LinkList *L)
int i,temp;
L->head = (Link*)malloc(sizeof(Link)); L->head->next=NULL;
L->tail = NULL;
L->len=0 ;
i = (int)rand();
temp = i - 5;
for(; i > temp; i --)

ListInsert_front_L(L, i);

return OK;


void Union(LinkList *a, LinkList *b, LinkList *c)

Link *ap, *bp, *cp, *tp;
c->head = (Link*)malloc(sizeof(Link));
c->len = 0;
c->tail = NULL;
cp = (Link*)malloc(sizeof(Link));
ap = a->head->next;
bp = b->head->next;
cp = c->head->next;
while(ap && bp)

if(ap->data<bp->data)

cp->data = ap->data;
ap = ap->next;

else

cp->data = bp->data;
bp = bp->next;

tp = (Link*)malloc(sizeof(Link));
cp->next = tp;
cp = tp;
c->len++;

while(ap)

cp->data = ap->data;
ap = ap->next;
if(ap)
tp = (Link*)malloc(sizeof(Link));
cp->next = tp;
cp = tp;
c->len++;

while(bp)

cp->data = bp->data;
bp = bp->next;
if(bp)
tp = (Link*)malloc(sizeof(Link));
cp->next = tp;
cp = tp;
c->len++;

cp->next=NULL;

int main()

LinkList *A, *B, *C;
ListCreat_L(A);
ListCreat_L(B);
printf("随机生成线性表A:");
ListTraverse_L(A);
printf("\n随机生成线性表B:");
ListTraverse_L(B);
Union(A, B, C);
printf("\nA、B表的交集线性表C:");
ListTraverse_L(C);
system("PAUSE");
return 0;
追问

编译是没错了,但是无法执行,这。。。

追答

能运行,因为程序中使用随机发生器产生数据,因此运行后可直接看结果,不用输入任何数据的。你试试看

追问

运行之后说是应用程序错误,"0x004011c5"指令引用的"0xcccccccc"内存。该内存不能为"written"

追答

那说明你机器问题,两种解决办法,一是换台机器就可以了,二是不用随机发生器,能输入语句试一试,当然换台机器是最快的,因为程序是可以运行的。

追问

LinkList *A, *B, *C;
你只是给指针ABC分配内存,但是没有给ABC指向的地址分配内存,所以变成了空指针。
应该加A = (LinkList*) malloc(sizeof(LinkList));
B = (LinkList*) malloc(sizeof(LinkList));
C = (LinkList*) malloc(sizeof(LinkList));

追答

不用,ABC通过函数传递参数的方法,分别都得到了各自的链表的首地址,在各自的函数中,有分配单元的语句。如:建立链表时的L->head = (Link*)malloc(sizeof(Link)); L->head->next=NULL;插入数据时的q=(Link*)malloc(sizeof(Link));
合并链表时的c->head = (Link*)malloc(sizeof(Link));
这不都是分配单元吗,链表的作用是把分配的单元用指针这个链给串起来就形成链表,ABC只是各链表的表头而已。

追问

LinkList *A, *B, *C;
执行这步后,A内存的大小就4个字节吧!,他没有指向任何地址,他怎么又有A->head呢?
你先去比较比较A和&A的值吧!
typedef struct LNode
ElemType data;
struct LNode *next;
Link;
一个*Link的内存都至少有4个字节吧,何况一个LinkList有*head,*tail,及len。所以A->head是空指针问题,
typedef struct
Link *head, *tail;
int len;
LinkList;

追答

看来你还是没有明白指针和指针指向单元的区别,指针就是一个地址,当它没有任何指向时就是一个地址,一个字节而已,分配单元后才有你说的4个字节,LinkList类型有head,tail两个指针,及len整型数据,这是绝对正确的,但一个指针变量是这样一个类型,只能说明当指针分配了一个指向这样类型的单元时,指针得到这4个字节单元的首地址,而这个地址是计算机从内存中按一定方式分配的,是程序设计时并不确定的,不是分配单元时这4个字节中放置的任何一个内容。说白了,指针就是如00F7H这么样的一个值,它不可能拥有4个字节。

追问

算我搞错了一个指针的内存大小了吧!这句话“分配单元后才有你说的4个字节,LinkList类型有head,tail两个指针,及len整型数据,这是绝对正确的,但一个指针变量是这样一个类型,只能说明当指针分配了一个指向这样类型的单元时,指针得到这4个字节单元的首地址”是你说的吧!很对,然后你在看看你程序LinkList *A, *B, *C,你有给他们值吗?他们现在是空指针,怎么又有A->head?????????????

小C秋招面试算法题:合并k个有序数组合并k个有序链表(分治思想)

写在前面

目前大部分公司的秋招都已经结束,博主小C也在昨天10.31结束了秋招最后一场面试。最近2个月的时间,做的事情大概就是投简历、刷题、笔试、复习八股文、面试,11月到来了,新的一个月开始,忽然感觉一切都是新的,可以放松一下近两月的紧绷状态,做一些自己的事情了,当然也要开始完成毕业论文啦。

参加的所有面试,结束之后都进行了复盘记录,以后有时间整理出来,写写这一段面试经历,分享面经。博主小C就读于双非一本大学,Java后端选手,这一段时间过来,感触还是很多~ ,其实自己并不是大佬级别的,只是勤勤恳恳,不算差而已。

今天先记录一下面试中经常考察的两个算法题,主要为了总结以作备忘,算法思想还是很重要的,也希望能帮助到有需要的朋友。

高频出现在面试中的考察的题目:合并k个有序数组合并k个有序链表

一、合并k个有序数组

看到这道题目,可以先联想到合并两个有序数组。所以,k个就可以比作很多个合并,每次合并两个数组。

1、合并两个有序数组

那先来看看合并两个有序数组怎么写。

public static int[] mergeTwoArray(int[] a1, int[] a2) {
    int m = a1.length, n = a2.length;
    int[] temp = new int[m + n];
    int i = 0, j = 0, idx = 0;
    while (i < m || j < n) {
        if (i == m) {//a1遍历完
            temp[idx++] = a2[j++];
        } else if (j == n) {
            temp[idx++] = a1[i++];
        } else if (a1[i] >= a2[j]) {
            temp[idx++] = a2[j++];
        } else if (a1[i] < a2[j]) {
            temp[idx++] = a1[i++];
        }
    }
    return temp;
}

看看代码,是不是感觉还行,思路很直接:创建一个新数组,来存放合并结果,每次就比较一下a1a2的每个元素,小的就先加到结果数组中,比较到一个数组末尾后,如果另一个还有元素,直接加上temp数组就OK了。

2、合并k个有序数组

合并两个有序数组可以如此操作,那合并k个该怎么操作?

实际上,按合并两个的思路,我们可以先拿两个出来合并,合并后的新数组再跟后面的数组进行合并,试试看!

/**
 * 从前往后每两个数组合并
*/
public static int[] sort(int[][] a) {
    int row = a.length, col = a[0].length;
    int i;
    int[] last = a[0];
    for (i = 1; i < row; i++) {
        last = mergeTwoArray(last, a[i]);
    }
    return last;
}

为了方便,我使用一个二维数组保存这k个有序数组,每一行就代表一个有序数组,就像以下这样存储。

int[][] a ={{1, 3, 3, 5, 10},
            {3, 5, 7, 15, 18},
            {2, 15, 17, 18, 20}};

写一个main方法,测试一下

public static void main(String[] args) {
    int[][] a =
    {{1, 3, 3, 5, 10},
     {3, 5, 7, 15, 18},
     {2, 15, 17, 18, 20}};
    int[] result = sort(a);
    for (int num : result)
        System.out.print(num + " ");
}

合并结果:1 2 3 3 3 5 5 7 10 15 15 17 18 18 20

到这里算是一种可以的解法了,但分析一下时间复杂度sort()方法O(n),mergeTwoArray方法O(n),双重嵌套就是O(n2)。

3、分治实现合并k个有序数组

所以看看有什么优化的方法,每个合并都是一个子问题,一时就想到分治算法,分为前后半段合并,然后细分也是如此。写一个merge方法。

public static int[] merge(int[][] a, int left, int right) {
    if (left == right)
        return a[left];
    if (left > right)
        return new int[0];

    int mid = (right - left) / 2 + left;
    int[] leftArray = merge(a, left, mid);
    int[] rightArray = merge(a, mid + 1, right);

    return mergeTwoArray(leftArray, rightArray);
}

leftright的意思就是:每次合并分为left~mid、mid + 1~right的数组,就是分治的思想,对左半段和右半段分别处理,然后再进行归并。

public static void main(String[] args) {
    int[][] a =
    {{1, 3, 3, 5, 10},
     {3, 5, 7, 15, 18},
     {2, 15, 17, 18, 20}};
    int[] result = merge(a, 0, a.length - 1);
    for (int num : result)
        System.out.print(num + " ");
}

合并结果:1 2 3 3 3 5 5 7 10 15 15 17 18 18 20

二、合并k个有序链表

这个题目的思想类似上面合并数组,只是以链表的形式呈现。

首先同样看看如何合并两个有序链表,LeetCode21 合并两个有序链表这个题目是完全一样的,可以练练。

链表结点的结构是这样的:

public class ListNode {
     int val;
     ListNode next;
     ListNode() {}
     ListNode(int val) { 
         this.val = val; 
     }
     ListNode(int val, ListNode next) { 
         this.val = val; 
         this.next = next; 
     }
}

1、合并两个有序链表

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if(l1 == null && l2 == null)
        return l1;
    else if(l1 == null)
        return l2;
    else if(l2==null)
        return l1;

    ListNode head = new ListNode(0);
    ListNode pre = head;//辅助指针保存当前比较的位置,准备下个next

    while(l1 != null && l2 != null){
        if(l1.val <= l2.val){
            pre.next = l1;
            l1 = l1.next;
        }
        else{
            pre.next = l2;
            l2 = l2.next;
        }
        pre = pre.next;//经过一次比较之后,更新位置,指向下一个
    }
    if(l1 != null)
        pre.next = l1;
    else
        pre.next = l2;

    return head.next;
}

对于链表的操作,一般就是修改指针的指向,并使用辅助结点进行实现。上面程序的结构可以对于合并两个有序数组,理解起来更容易。

合并两个有序链表这道题在LeetCode上标记是简单,而合并k个有序数组标记了困难,可见还是有一定的难度。

不过,完全不用慌,也许你理解了合并两个有序链表之后,这道题实际采用上面的分治思想或者每次合并两个的方案,都是比较简单的事情了,只需要在添加一个方法。

2、合并k个有序链表

往简单想,真的不难,来看看~

同样保留合并两个有序链表mergeTwoLists方法,只需再增加一个merge方法,就搞定!

public ListNode merge(ListNode[] lists, int l, int r) {//分治,归并
    if (l == r) {
        return lists[l];
    }

    if (l > r) {
        return null;
    }

    int mid = (l + r) >> 1;//中点

    ListNode node1 = merge(lists, l, mid);//左半段归并排序
    ListNode node2 = merge(lists, mid + 1, r);//右半段归并排序
    return mergeTwoLists(node1, node2);//合并两段
}

然后在主方法直接调用merge就完成了。

public ListNode mergeKLists(ListNode[] lists) {
    ListNode ans = null;
    ans = merge(lists,0,lists.length - 1);
    return ans;
}

后语

这篇记录的是面试中常见的算法考察题目,由浅入深,更好理解,有时候一个算法思想可以融会贯通,这个过程就需要千锤百炼了,以后还需要更进一步学习。

今天,11月1号,是我秋招结束的第一天,在此记录。以后还会把我的面试经历分享给大家,希望大家一起成长,收获满满~



如果觉得不错欢迎“一键三连”哦,点赞收藏关注,评论提问建议,欢迎交流学习!一起加油进步,我们下篇见!


本篇内容首发我的CSDN博客:https://csdn-czh.blog.csdn.net/article/details/120883869

以上是关于c语言有序链表合并,我找不到问题所在,求纠错!!的主要内容,如果未能解决你的问题,请参考以下文章

[ 链表OJ题--C语言 ] 合并两个有序链表

02-线性结构1 两个有序链表序列的合并

求C语言 数据结构中的链表创建,插入和删除代码

经典算法——合并K个有序链表

将两个有序链表合并,合并后仍然有序

有序链表合并