C语言练习-day21

题目:试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为0)。

输入:不带头结点的链表个元素的值,类型为int,以9999结束。

输出:逆置单链表之后,输出单链表。

优化目标:无。

算法思想:将头结点摘下,,然后从第一个结点开始,依次插入到头结点的后面(头插法),直到最后一个结点为止,这样就实现了链表的逆置。

#include
#include

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

//逆置链表
void ReverseList(LinkList &L){
    LNode *p = L->next,*s;
    L->next = NULL;
    while(p != NULL){
        s = p->next;
        p->next = L->next;
        L->next = p;
        p = s;
    }
}


//创建链表
void creatList(LinkList &L){
    LNode *s,*r;
    int x;
    printf("请输入链表元素值(以9999结束):");
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    r = L;
    scanf("%d",&x);
    while(x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        s->next = NULL;
        r = s;
        scanf("%d",&x);
    }
}

//输出链表
void PrintList(LinkList L){
    LNode *p = L->next;
    printf("链表元素有:");
    while(p!=NULL){
        printf("%d   ",p->data);
        p = p->next;
    }
    printf("\n");
}



int main() {
	LinkList L;
	creatList(L);
	PrintList(L);
	ReverseList(L);
	PrintList(L);
	
	return 0;
}

题目:有一个带头结点的单链表工,设计一个算法使其元素递增有序。

输入:不带头结点的链表个元素的值,类型为int,以9999结束。

输出:删除所有值为x的结点后输出单链表。

优化目标:无。

算法思想:算法思想:采用直接插入排序算法的思想,先构成只含一个数据结点的有序单链表,然后依次为人所扫描单链表中剩下的结点*p (直至p==NULL为止),在有序表中通过比较查找插入p的前驱结点*pre,然后将*p插入到*pre之后。

#include
#include

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

//链表排序
void Sort(LinkList &L){
    LNode *p = L->next,*pre;
    LNode *r = p->next;
    p->next = NULL;
    p = r;
    while(p!=NULL){
        r = p->next;
        pre = L;
        while(pre->next!=NULL&&pre->next->datadata){
            pre = pre->next;
        }
        p->next = pre->next;
        pre->next = p;
        p = r;
    }
}

//创建链表
void creatList(LinkList &L){
    LNode *s,*r;
    int x;
    printf("请输入链表元素值(以9999结束):");
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    r = L;
    scanf("%d",&x);
    while(x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        s->next = NULL;
        r = s;
        scanf("%d",&x);
    }
}

//输出链表
void PrintList(LinkList L){
    LNode *p = L->next;
    printf("链表元素有:");
    while(p!=NULL){
        printf("%d   ",p->data);
        p = p->next;
    }
    printf("\n");
}



int main() {
	LinkList L;
	creatList(L);
	PrintList(L);
	Sort(L);
	PrintList(L);
	
	return 0;
}

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

输入:不带头结点的链表个元素的值,类型为int,以9999结束。

输出:删除所有值为x的结点后输出单链表。

优化目标:无。

算法思想:因为链表是无序的,所以只能逐个结点进行检查,执行删除前二十。

#include
#include

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

//删除介于给定值的之间的元素
void del_s_t(LinkList &L,int s,int t){
	LNode *pre = L,*p = L->next,*q;
	while(p!=NULL){
		if(p->data>s && p->datanext;
            pre->next = p;
            free(q);
		}
		else{
			pre = p;
			p = p->next;
		}
	}
}


//创建链表
void creatList(LinkList &L){
    LNode *s,*r;
    int x;
    printf("请输入链表元素值(以9999结束):");
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    r = L;
    scanf("%d",&x);
    while(x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        s->next = NULL;
        r = s;
        scanf("%d",&x);
    }
}

//输出链表
void PrintList(LinkList L){
    LNode *p = L->next;
    printf("链表元素有:");
    while(p!=NULL){
        printf("%d   ",p->data);
        p = p->next;
    }
    printf("\n");
}



int main() {
	LinkList L;
	creatList(L);
	PrintList(L);
	int s,t;
	printf("请输入下界:");
	scanf("%d",&s);
	printf("请输入上界:");
	scanf("%d",&t);
	del_s_t(L,s,t);
	PrintList(L);
	
	
	return 0;
}

题目:給定两个单链表,编写算法找出两个链表的公共结点。

输入:不带头结点的链表个元素的值,类型为int,以9999结束。

输出:删除所有值为x的结点后输出单链表。

优化目标:无。

算法思想:*p指向的是第一个链表L1,q指向第二个链表L2,创建一个单链表L,首先对L2遍历,在每遍历L2的一个结点,然后对L1遍历看是否有相同的结点,如果有就创建新结点然后插到L中,最后返回L。(我的想法错了,题目要求是找结点相同,而不是相同元素,所以看了答案然后照着写了后面的一个)。

#include
#include

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

//查找两个链表的公共结点
LinkList similarity(LinkList L1,LinkList L2){
	LinkList L = (LinkList)malloc(sizeof(LNode));
	L->next = NULL;
	LNode *s,*r,*p,*q;
	r = L;
	p = L1->next;
	q = L2->next;
	while(q!=NULL){
		while(p!=NULL){
			if(q->data == p->data){
				s = (LNode *)malloc(sizeof(LNode));
				s->data = q->data;
				r->next = s;
				s->next =NULL;
				r = s;
			}
			p = p->next;
		}
		p = L1->next;
		q = q->next;
	}
	return L;
	
}


//创建链表
void creatList(LinkList &L){
    LNode *s,*r;
    int x;
    printf("请输入链表元素值(以9999结束):");
    L = (LinkList)malloc(sizeof(LNode));
    L->next = NULL;
    r = L;
    scanf("%d",&x);
    while(x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        s->next = NULL;
        r = s;
        scanf("%d",&x);
    }
}

//输出链表
void PrintList(LinkList L){
    LNode *p = L->next;
    printf("链表元素有:");
    while(p!=NULL){
        printf("%d   ",p->data);
        p = p->next;
    }
    printf("\n");
}



int main() {
	LinkList L1,L2,L;
	creatList(L1);
	PrintList(L1);
	
	creatList(L2);
	PrintList(L2);
	
	L = similarity(L1,L2);
	printf("已找到\n");
	PrintList(L);
	return 0;
}

算法思想:接下来我们试着去寻找一个线性时间复杂度的算法。先把问题简化:如何判断两个单向链表有没有公共结点?应注意到这样一个事实:若两个链表有一个公共结点,则该公共结点之后的所有结点都是重合的,即它们的最后一个结点必然是重合的。因此,我们判断两个链表是不是有重
合的部分时,只需要分别遍历两个链表到最后一个结点。 若两个尾结点是一样的,则说明它们有
公共结点,否则两个链表没有公共结点。然而,在上面的思路中,顺序遍历两个链表到尾结点时,并不能保证在两个链表上同时到达尾结点。这是因为两个链表长度不一定一样。但假设一个链表比另一个长 k个结点,我们先在长的链表上遍历k个结点,之后再同步遍历,此时我们就能保证同时到达最后一个结点。由于两个链表从第一个公共结点开始到链表的尾结点,这一部分是重合的,因此它们肯定也是同时到达第一公共结点的。 于是在遍历中,第一个相同的结点就是第一个公共的结点。

#include
#include

typedef struct LNode{
    int data;
    struct LNode *next;
}LNode,*LinkList;

int Length(LinkList L){
	LNode *p = L->next;
	int count = 1;
	while(p!=NULL){
		count++;
		p = p->next;
	}
	return count;
}

//查找两个链表的公共结点
LinkList similarity(LinkList L1,LinkList L2){
	int len1 = Length(L1),len2 = Length(L2),dist;
	LinkList longList,shortList;
	if(len1>len2){
		longList = L1->next;
		shortList = L2->next;
		dist = len1-len2;
	}
	else{
		longList = L2->next;
		shortList = L1->next;
		dist = len2-len1;
	}
	
	while(dist--){
		longList = longList->next;
	}
	while(longList!=NULL){
		if(longList == shortList){
			return longList;
		}
		else{
			longList = longList->next;
			shortList = shortList->next;
		}
	}
	
	return NULL;
	
}


//创建链表
void creatList(LinkList &L1,LinkList &L2){
    LNode *s,*r,*p;
    int x;
    
    
    L1 = (LinkList)malloc(sizeof(LNode));
    
    L2 = (LinkList)malloc(sizeof(LNode));
    
    L1->next = NULL;
    r = L1;
    
    L2->next = NULL;
	p = L2;
    
    s = (LNode *)malloc(sizeof(LNode));
    s->data = 3;
    r->next = s;
    s->next = NULL;
    r = s;
    s = (LNode *)malloc(sizeof(LNode));
    s->data = 4;
    p->next = s;
    s->next = NULL;
    p = s;
    
    p->next = r;
//    s = (LNode *)malloc(sizeof(LNode));
//    s->data = 5;
//    p->next = s;
//    r->next = s;
//    s->next = NULL;
//    p = s;
//    r = s;
    
    
	printf("请输入链表元素值(以9999结束):");
    scanf("%d",&x);
    while(x!=9999){
        s = (LNode *)malloc(sizeof(LNode));
        s->data = x;
        r->next = s;
        s->next = NULL;
        r = s;
        scanf("%d",&x);
    }
}

//输出链表
void PrintList(LinkList L){
    LNode *p = L->next;
    printf("链表元素有:");
    while(p!=NULL){
        printf("%d   ",p->data);
        p = p->next;
    }
    printf("\n");
}



int main() {
	LinkList L1,L2,L;
	creatList(L1,L2);
	PrintList(L1);
	
	PrintList(L2);
	
	L = similarity(L1,L2);
	printf("已找到\n");
	PrintList(L);
	return 0;
}

今日总结:做了几个单链表的题,还是感觉不错的,我觉得需要好好加强对单链表的代码练习,还要多做多练。明天继续。

你可能感兴趣的:(数据结构,c语言,算法)