• 王道数据结构【链表】部分代码实现(C语言)


    数据结构专栏:

    1. 王道数据结构【顺序表】部分代码实现(C语言)
    2. 王道数据结构【链表】部分代码实现(C语言)
    3. 王道数据结构【栈队列及其应用】部分代码实现(C语言)
    4. 王道数据结构【二叉树】部分代码实现(C语言)
    5. 王道数据结构【图】部分代码实现(C语言)
    6. 王道数据结构【查找排序】部分代码实现(C语言)

    递归删除不带头结点链表中指定值

    /*
    	设计一个递归算法,删除一个不带头结点的单链表中所有值为x的节点
    	分析:
    		首先我们要创建单链表,并赋值,然后递归去判断值,进行删除
    */
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    struct Link
    {
    	int value;
    	struct Link *next;
    };
    void deleteX(Link *&p, int delNum) {//这里的第一个函数参数必须是引用值,不然会导致断链
    	struct Link *pre;//定义一个指针,进行删除
    	if (p == NULL) return;
    	if (p->value == delNum) {
    		pre = p;
    		p = p->next;
    		free(pre);
    		deleteX(p, delNum);
    	}
    	else
    		deleteX(p->next, delNum);
    }
    Link *create() {
    	struct Link *p, *rear, *head;
    	head = (struct Link *)malloc(sizeof(struct Link));
    	rear = (struct Link *)malloc(sizeof(struct Link));
    	head = NULL;
    	rear = NULL;
    	int value;
    	printf("请输入链表各节点的值,以9999结束:");
    	scanf("%d", &value);
    	while (value != 9999) {//依次创建节点
    		p = (struct Link *)malloc(sizeof(struct Link));//创建一个新的节点
    		p->value = value;
    		p->next = NULL;
    		if (head == NULL) {
    			rear = p;
    			head = p;
    		}
    		else {
    			rear->next = p;
    			rear = p;
    		}
    		scanf("%d", &value);
    	}
    	rear->next = NULL;
    	return head;
    }
    Link *create2() {
    	struct Link *p, *rear, *head;
    	head = (struct Link *)malloc(sizeof(struct Link));
    	head = NULL;
    	int value;
    	printf("请输入链表各节点的值,以9999结束:");
    	scanf("%d", &value);
    	while (value != 9999) {//依次创建节点
    		p = (struct Link *)malloc(sizeof(struct Link));
    		p->value = value;
    		p->next = NULL;
    		if (head == NULL) {
    			head = p;
    		}
    		else {
    
    			p->next = head->next;
    			head->next = p;
    		}
    
    		scanf("%d", &value);
    	}
    	return head;
    }
    int main() {
    	int delNum;
    	struct Link *head, *q;
    	head = create();
    	q = head;
    	printf("打印链表:");
    	while (q != NULL) {
    		printf("%d ", q->value);
    		q = q->next;
    	}
    	q = head;
    	printf("请输入想要删除的节点的值:");
    	scanf("%d", &delNum);
    	deleteX(q, delNum);
    	printf("删除后链表:");
    	while (q != NULL) {
    		printf("%d ", q->value);
    		q = q->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    带头结点链表删除指定值

    /*
    	在带头结点的单链表L中,删除所有值为X的节点,并释放其空间,假设值为X的节点不唯一
    	分析:
    		和上题相似,只是多了一个头结点。
    */
    struct Link {
    
    	int data;
    	struct Link *next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void deleteX(Link *p,int delNum) {
    	/*struct Link* q;//这是递归方法
    	if (p == NULL) return;
    	if (p->data==delNum) {
    		q = p;
    		p = p->next;
    		free(q);
    		deleteX(p,delNum);
    	}
    	else {
    		deleteX(p->next, delNum);
    	}*/
    	//不采取递归,直接遍历
    	struct Link *pre = p, *q = p->next,*r;
    	while (q) {
    		if (q->data==delNum) {
    			r = q;//r指向待删除节点
    			q = q->next;//
    			pre->next = q;//删除节点
    			free(r);//释放节点
    		}
    		else {
    			pre = q;
    			q = q->next;
    			
    		}
    	}
    }
    
    int main() {
    	//创建节点
    	struct Link *head = (struct Link*)malloc(sizeof(struct Link));
    	struct Link *q = (struct Link*)malloc(sizeof(struct Link));
    	q = head;
    	head->next = NULL;
    	int n,data,delNum;
    	printf("请输入节点个数:");
    	scanf("%d",&n);
    	for (int i = 0; i < n;i++) {
    		printf("请输入第%d个节点值:",i+1);
    		struct Link *p = (struct Link*)malloc(sizeof(struct Link));
    		scanf("%d",&data);
    		p->data = data;
    		head->next = p;
    		head = p;
    	
    	}
    	head->next = NULL;//这里要将指针的next指向NULL,不然后面的判断会出问题,而且这也是应该养成的好习惯
    	head = q;//head回到头结点
    	printf("当前链表值为:");
    	while (head->next) {
    		printf("%d ",head->next->data);
    		head = head->next;
    	}
    	printf("\n");
    	printf("请输入要删除的值:");
    	scanf("%d",&delNum);
    	head = q;//head回到头结点
    	deleteX(head,delNum);
    	printf("删除后链表值为:");
    	while (head->next) {
    		printf("%d ", head->next->data);
    		head = head->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    反向输出链表值

    /*
    	有一带头结点的链表,设计一算法从尾到头的输出每个节点的值。
    	分析:
    		这种类型就有点像是栈的性质,我们可以利用递归来处理,出口便是尾元素
    */
    struct Link {
    	int data;
    	struct Link* next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void reverseOutput(Link *p) {
    	if (p == NULL) return;
    	else {
    		reverseOutput(p->next);
    		printf("%d ",p->data);
    	}
    	
    }
    int main() {
    	int n,data;
    	printf("请输入创建链表的节点个数:");
    	scanf("%d",&n);
    	struct Link *q;
    	struct Link *head =(struct Link*) malloc(sizeof(struct Link));
    	head->next = NULL;
    	q = head;
    	for (int i = 0; i < n;i++) {
    		struct Link *newP = (struct Link*) malloc(sizeof(struct Link));
    		printf("请输入第一个节点的值:");
    		scanf("%d",&data);
    		newP->data = data;
    		newP->next = NULL;
    		head->next = newP;
    		head = head->next;//head要始终指向最新节点
    	}
    	head->next = NULL;
    	head = q;//最后head要指向头结点
    	reverseOutput(head->next);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    带头结点的单链表删除最小值节点

    /*
    	删除链表中唯一的最小值
    	分析:
    		目前能想到的就是遍历整个链表,记录下最小节点的指针,然后进行删除,时间复杂度为O(n).
    */
    struct Link {
    	int data;
    	struct Link* next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void deleteMin(Link *p) {
    	struct Link *preMinp = p, *minP = p->next,*preQ=p->next, *q = p->next->next,*f;
    	while (q) {
    		if (q->data < minP->data) {//如果比当前值更小
    			minP = q;//更换
    			preMinp = preQ;//前驱一起更换
    		}
    		preQ = q;//继续前进
    		q = q->next;
    	}
    	f = minP;
    	preMinp->next = minP->next;//删除
    	free(f);//释放
    
    }
    int main() {
    		int n,data;
    		printf("请输入创建链表的节点个数:");
    		scanf("%d",&n);
    		struct Link *q;
    		struct Link *head =(struct Link*) malloc(sizeof(struct Link));
    		head->next = NULL;
    		q = head;
    		for (int i = 0; i < n;i++) {
    			struct Link *newP = (struct Link*) malloc(sizeof(struct Link));
    			printf("请输入第一个节点的值:");
    			scanf("%d",&data);
    			newP->data = data;
    			newP->next = NULL;
    			head->next = newP;
    			head = head->next;//head要始终指向最新节点
    		}
    		head->next = NULL;
    		head = q;//最后head要指向头结点
    		printf("打印链表:");
    		while (head->next) {
    			printf("%d ", head->next->data);
    			head = head->next;
    		}
    		head = q;
    		deleteMin(head);
    		printf("删除后链表值为:");
    		while (head->next) {
    			printf("%d ", head->next->data);
    			head = head->next;
    		}
    		return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    带头结点单链表就地逆置

    /*
    	就地逆置链表
    	分析:
    		我们采用头插法进行逆置。
    */
    struct Link {
    	int data;
    	struct Link* next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    //void reverse(Link *h) {
    	//struct Link *pre = h, *p = h->next, *q = h->next,*r;
    	pre记录操作节点p上一个节点,q记录第一个节点,之后需要指向NULL,r用于指向每一次操作时p的后一个节点,防止断链
    	//while (p) {//遍历操作,修改指针指向
    	//	r = p->next;
    	//	p->next = pre;
    	//	pre = p;
    	//	p = r;
    	//}
    	//h->next = pre;//头指针指向最后一个节点
    	//q->next = NULL;//第一个节点指向NULL,不然就是循环单链表了
    	
    
    	//我们也可以采用头插法进行逆置,两个方法的时间复杂度均为O(N)
    	struct Link *l = h, *p = h->next,*r;
    	l->next = NULL;
    	while (p) {
    		r = p->next;
    		p->next = l->next;
    		l->next = p;
    		p = r;
    	}
    	h = l;
    }
    int main() {
    	struct Link *head = (struct Link*) malloc(sizeof(struct Link));
    	Link *createLink(int);
    	head = createLink(0);
    	reverse(head);
    	printf("逆置后链表值为:");
    	while (head->next) {
    		printf("%d ", head->next->data);
    		head = head->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    单链表排序

    /*
    	有一个带头结点的单链表L,设计一个算法使其递增有序
    	分析:
    		我们可以采用冒泡排序对其操作,使其递增有序,时间复杂度为O(n^2)。
    */
    
    struct Link {
    	int data;
    	struct Link *next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void bubbleSort(Link *h) {//冒泡排序
    	int flag = 0;//排序标志,产生过变动就置为1
    	int count = 0;//记录链表长度
    	struct Link *pre=h, *p = h->next,*r;
    	while (p) {
    		count++;
    		p = p->next;
    	}
    	p = h->next;
    	for (int i = 0; i < count;i++) {
    		flag = 0;
    		while (p->next) {//开始第i+1轮冒泡
    			if (p->data > p->next->data) {//前者大于后者,则需要交换
    				r = p->next->next;//r指向下一个节点,防止断链
    				pre->next = p->next;
    				p->next->next = p;
    				pre = p->next;
    				p->next = r;
    				flag = 1;//有改动,flag置为1
    			}
    			else {
    				pre = p;
    				p = p->next;
    			}
    		}
    		if (!flag) break;//若某一轮链表未作变换,则认定已经排好序,退出循环
    		pre = h;//重新从头开始遍历
    		p = h->next;
    	}
    }
    int main() {
    	Link* createLink(int);
    	struct Link *head;
    	head = createLink(0);
    	bubbleSort(head);
    	printf("排序后链表值为:");
    	while (head->next) {
    		printf("%d ", head->next->data);
    		head = head->next;
    	}
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    删除指定范围值

    /*
    	设一个带头结点的单链表所有元素的数据值无序,试编写函数删除表中介于给定的两个值(作为函数参数给出)之间的元素。
    	分析:
    		分别设置pre,p,r指针,遍历,符合条件便进行删除。
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void deleteNum(Link *h,int min,int max) {
    	struct Link *pre = h, *p = h->next, *r;
    	while (p) {
    		if (p->data>min&&p->data<max) {//符合条件,进行删除
    			r = p->next;
    			pre->next = p->next;
    			free(p);
    			p = r;
    		}
    		else {
    			pre = p;
    			p = p->next;
    		}
    	}
    }
    int main() {
    	int min, max;
    	struct Link*head;
    	Link *createLink(int);//创建链表的代码我单独封装了一个文件
    	void printfNowLink(Link*);
    	head = createLink(0);
    	printf("请输入要删除的值所在的范围:\n");
    	printf("min=");
    	scanf("%d",&min);
    	printf("max=");
    	scanf("%d", &max);
    	deleteNum(head,min,max);
    	printfNowLink(head);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    递增输出并删除

    /*
    	按递增次序输出单链表各节点的数据元素,并释放节点所占的存储空间。
    	分析:
    		我们可以先进行排序,然后依次输出,并释放节点空间,我们也可以直接进行遍历,找到目前最小值进行输出,然后释放,注意不要断链
    		我们这里采取第二种方式
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    #include 
    void printAndDel(Link *h) {
    	struct Link *pre = h, *p = h->next, *r,*min=h->next,*minPre=h;//为了操作的顺利进行,我们需要时刻保存节点的前驱与后继
    	int count = 0;
    	while (p) {
    		count++;
    		p = p->next;
    	}
    	p = h->next;
    	printf("输出顺序为:\n");
    	for (int i = 0; i < count;i++) {
    		while (p) {
    			if (p->data < min->data) {
    				minPre = pre;
    				min = p;
    			}
    			pre = p;
    			p = p->next;
    		}
    		printf("%d ",min->data);
    		r = min->next;
    		minPre->next = min->next;
    		free(min);
    		pre = minPre = h;
    		p = min = h->next;
    	}
    	printf("\n");
    }
    int main() {
    	struct Link *head;
    	Link *createLink(int);
    	void printfNowLink(Link*);
    	head = createLink(0);
    	printAndDel(head);
    	printfNowLink(head);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    按奇偶拆分成单链表

    /*
    	将一个带头结点单链表A分解成两个带头结点的单链表A和B,使得A中含有原表中序号为奇数的元素,B中为偶数,且保持其相对位置不变
    	分析:
    		首先我们需要分配一个节点空间为B作为头节点,然后设置一个flag,为0时认为是奇数,链给A,为1时认为是
    		偶数,连给B
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    #include 
    void divide(Link *lb,Link *la) {
    	int flag = 0;//做奇偶判定,因为奇数之后一定是偶数,偶数之后一定是奇数
    	struct Link *l=la, *p = la->next,*rb=lb,*ra=l;
    	l->next = NULL;//原链表头结点置空
    	while (p) {//要使其顺序不变,采用尾插法
    		if (!flag) {
    			ra->next = p;
    			ra = p;
    			flag = 1;
    		}
    		else {
    			rb->next = p;
    			rb = p;
    			flag = 0;
    		}
    		p = p->next;
    	}
    	ra->next = NULL;//要记得将末尾节点的指针指向NULL,不然就仍然是之前的指针,导致结果不正确
    	rb->next = NULL;
    }
    int main() {
    	struct Link *head;
    	Link *createLink(int);
    	void printfNowLink(Link *);
    	head = createLink(0);
    	struct Link *b = (struct Link*)malloc(sizeof(struct Link));//开辟节点空间
    	divide(b,head);
    	printfNowLink(b);
    	printf("\n");
    	printfNowLink(head);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    有序链表去重

    /*
    	在一个递增有序的线性表中,有数值相同的元素存在,若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。
    	分析:
    		对于这类去重,我们肯定需要进行遍历,而这道题给我们的是递增有序的序列,我们便可以进行一一比较,后一个元素与当前元素相同
    		时便删除当前元素
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    
    #include 
    #include 
    void deleteRep(Link *h) {
    	struct Link *pre = h, *p = h->next, *r;//删除节点必备三剑客
    	while (p->next) {
    		if (p->data==p->next->data) {//当前节点与后续节点值相同,则删除并释放空间
    			r = p->next;//必须先保存后续节点,防止断链
    			pre->next = p->next;
    			free(p);
    			p = r;
    			continue;
    		}
    		pre = p;
    		p = p->next;
    	}
    }
    int main() {
    	struct Link * head;
    	Link *createLink(int);
    	void printfNowLink(Link *);
    	head = createLink(0);
    	deleteRep(head);
    	printfNowLink(head);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    归并单链表

    /*
    	假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素递减的单链表,
    	并要求利用原来两个单链表的节点存放归并后的单链表。
    	分析:
    		因为链表递增,所以我们可以采用头插法进行处理,以a链为起始链,进行归并
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    
    void merge(Link *ha,Link *hb) {
    	struct Link *l = ha, *pa = ha->next, *pb = hb->next, *ra, *rb;
    	l->next = NULL;
    	while (pa&&pb) {
    		if (pa->data<pb->data) {
    			ra = pa->next;
    			pa->next = l->next;
    			l->next = pa;
    			pa = ra;
    		}
    		else {
    			rb = pb->next;
    			pb->next = l->next;
    			l->next = pb;
    			pb = rb;
    		}
    	}
    	while (pa) {
    		ra = pa->next;
    		pa->next = l->next;
    		l->next = pa;
    		pa = ra;
    	}
    	while (pb) {
    		rb = pb->next;
    		pb->next = l->next;
    		l->next = pb;
    		pb = rb;
    	}
    }
    int main() {
    	struct Link *ha,*hb;
    	Link *createLink(int);
    	void printfNowLink(Link *);
    	ha = createLink(0);
    	hb = createLink(0);
    	merge(ha,hb);
    	printfNowLink(ha);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    提取公共元素

    /*
    		设A、B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A、B中的公共元素产生单链表C,要求不破坏A、B节点
    		分析:
    			要求不破坏A、B节点,故我们需要重新创建分配节点空间,来进行连接。为寻找公共元素,每遍历A中的一个元素,都去
    			与B中元素一一比较,同则取值给另一空间节点,连接到C上。时间复杂度为O(n^2)。
    			因为这两个链表是递增有序的,那么我们可以设置两个指针同步比较,相同则加入c,不同小的那个往后移,直至到链表末尾
    			这样的时间复杂度为O(n).
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    #include 
    void linkCommon(Link *a, Link *b, Link *c ) {
    	struct Link *lc = c,*la=a->next,*lb=b->next,*rc=lc;
    	while (la) {
    		while (lb) {
    			if (la->data==lb->data) {//如果是公共元素
    				struct Link *p = (struct Link*)malloc(sizeof(struct Link));
    				p->data = la->data;
    				rc->next = p;//采用尾插法
    				rc = p;
    				break;
    			}
    			lb = lb->next;
    		}
    		la = la->next;
    		lb = b->next;
    	}
    	rc->next = NULL;//最后一个节点指针需要指向NULL。
    }
    void listCommon(Link *a,Link *b,Link *c) {
    	struct Link *rc = c, *la = a->next, *lb = b->next;
    	while (la&&lb) {
    		if (la->data==lb->data) {
    			struct Link *p = (struct Link*)malloc(sizeof(struct Link));
    			p->data = la->data;
    			p->next = NULL;
    			rc->next = p;
    			rc = p;
    			la = la->next;
    			lb = lb->next;
    		}
    		else {
    			la->data < lb->data ? la = la->next : lb = lb->next;
    		}
    	}
    	rc->next = NULL;
    }
    int main() {
    	struct Link *a, *b;
    	Link *createLink(int);
    	void printfNowLink(Link *);
    	a = createLink(0);
    	b = createLink(0);
    	struct Link *c = (struct Link*)malloc(sizeof(struct Link));
    	c->next = NULL;
    	//linkCommon(a,b,c);
    	listCommon(a,b,c);
    	printfNowLink(c);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    求两链表交集

    /*
    	已知两个链表A、B分别表示两个集合,其元素递增排列,编制函数,求A与B的交集,并存放于A链表中。
    	分析:
    		与上题类似,因为链表本身递增排序,我们可以设置两个指针,同时遍历A、B链表,同则保留,异则删除
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    
    #include 
    void listCommon(Link *a,Link *b) {
    	struct Link  *pA = a->next, *pB = b->next,*r,*la=a;//用la指向a,便可直接链在a后面
    	la->next = NULL;
    	while (pA&&pB) {
    		if (pA->data==pB->data) {
    			la->next = pA;
    			la = pA;
    			pA = pA->next;
    			pB = pB->next;
    		}
    		else {
    			pA->data < pB->data ? pA = pA->next : pB = pB->next;
    		}
    	}
    	la->next = NULL;
    }
    int main() {
    	struct Link *a, *b;
    	Link *createLink(int);
    	void printfNowLink(Link *);
    	a = createLink(0);
    	b = createLink(0);
    	listCommon(a,b);
    	printfNowLink(a);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    判断是否是子序列

    /*
    	存在两个单链表序列A、B,设计函数判断B是否为A的子序列。
    	分析:
    		最直接的方法:循环遍历,从A链的第一个元素开始与B链对比,如遇见不同,从A链下一个又开始,直至到达链尾
    */
    struct Link {
    	int data;
    	struct Link *next;
    
    };
    
    #include 
    
    void subList(Link *a,Link *b) {
    	struct Link *la = a ,*pA = la->next, *pB = b->next;
    	while (pA&&pB) {
    		if (pA->data==pB->data) {//相等继续对比下一个
    			pA = pA->next;
    			pB = pB->next;
    		}
    		else {
    			pB = b->next;//pb从头开始与pa对比
    			la = la->next;//失败一次,la往后移动一个节点
    			pA = la->next;//pa从下一个节点又开始
    		}
    	}
    	pB == NULL ? printf("true") : printf("false");//如果pb为NULL,说明已比对完成
    	
    }
    int main() {
    	struct Link *a, *b;
    	Link *createLink(int);
    	a = createLink(0);
    	b = createLink(0);
    	subList(a,b);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    判断循环双链表是否对称

    // createDouLoopLink.cpp
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    struct Link {
    	int data;
    	struct Link *next;
    	struct Link *pre;
    };
    Link *createDouLoopLink() {
    	int n, data;
    	struct Link *head = (struct Link *)malloc(sizeof(struct Link));
    	head->next = NULL;
    	head->pre = NULL;
    	struct Link *p = head;
    	printf("请输入节点个数:n=");
    	scanf("%d", &n);
    	for (int i = 0; i < n; i++) {
    		printf("请输入第%d个节点值:", i + 1);
    		scanf("%d", &data);
    		struct Link *newP = (struct Link*)malloc(sizeof(struct Link));
    		newP->data = data;
    		newP->pre = p;
    		p->next = newP;
    		p = newP;
    	}
    	p->next = head;
    	head->pre = p;
    	return head;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    将B链表链接到A链表

    /*
    	有两个循环单链表,链表头指针分别为h1和h2,编写一个函数将链表h2连接到h1之后,要求连接后的链表仍保持循环链表形式。
    	分析:
    		首先我们要找到h1的尾结点,找到尾结点后将尾结点的next指向h2的首节点,然后找到h2的尾结点,将其next指针指向h1,
    		就大功告成了。
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    #include 
    void linkTwoLists(Link *h1,Link *h2) {
    	struct Link *p1 = h1->next, *p2 = h2->next;
    	while (p1->next != h1) p1 = p1->next;//这里要去判断p1->next是否等于h1,进而判断出是否到达尾结点
    	p1->next = p2;
    	while (p2->next != h2) p2 = p2->next;
    	p2->next = h1;
    	free(h2);//释放h2
    }
    int main() {
    	struct Link *h1, *h2,*p;
    	Link *createSinLoopLink();
    	h1 = createSinLoopLink();
    	h2 = createSinLoopLink();
    	linkTwoLists(h1,h2);
    	p = h1->next;
    	while (p!=h1) {
    		printf("%d ",p->data);
    		p = p->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    循环输出最小值并删除

    /*
    	设有一个带头结点的单链表,其节点均为正值,设计一个算法,反复找出单链表中最小值输出并删除,直到单链表为空,最后删除头结点
    	分析:
    		按照以往的经验,我们需要遍历它,为了保证不断链,我们需要设置pre,p,minPre,min,r等5个指针。
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #include 
    #include 
    void inputAndDeleteLink(Link *h) {
    	struct Link *pre = h, *minPre = h, *p = h->next, *min = h->next, *r;
    	while (h->next!=h) {//如果头结点后面还有值,说明未结束
    		while (p!=h) {//寻找最小值
    			if (min->data>p->data) {
    				minPre = pre;
    				min = p;
    			}
    			pre = p;
    			p = p->next;
    		}
    		printf("%d ",min->data);
    		r = min->next;
    		minPre->next = min->next;//删除当前最小值
    		free(min);//释放节点空间
    		p = h->next;//又重头开始遍历
    		pre = h;
    		minPre = h;
    		min = h->next;
    	}
    	free(h);//最后释放头结点
    }
    int main() {
    	struct Link *head;
    	Link *createSinLoopLink();
    	head = createSinLoopLink();
    	inputAndDeleteLink(head);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    按频度排序

    /*
    	给一个非循环双向链表增加一个freq值,用以表示它的访问频率,每访问一次freq就+1,然后需要将该链表按照非增的顺序
    	排列,同时最近访问的节点排在相同频度节点的前面,以便使频繁访问的节点总是靠近表头。试编写符合上述要求的Locate(L,x)
    	函数,该运算为函数过程,返回找到节点的地址,类型为指针型。
    
    	分析:
    		这道题咋一看很唬人,还引入了一个新概念,其实并不难,拆分开来其实就是 查找+排序;我们需要先找到我们要访问的节点
    		,更改它的freq值,然后按照freq值的大小从表头寻找插入位置,这样便完成了一次locate操作。
    */
    struct Link {
    	int data;
    	struct Link *pre;
    	struct Link *next;
    	int freq;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    void locate(Link *h,int num) {
    	int flag = 0;//找到标志
    	struct Link *pre=h, *p = h->next, *t,*preQ=h,*q;
    	while (p) {
    		if (p->data==num) {//如果找到
    			flag = 1;//表示找到
    			p->freq++;//freq+1
    			t = p;//将该节点保存起来
    			if (p->next) {
    				pre->next = p->next;//将该节点抠出来
    				p->next->pre = pre;
    			}
    			else {
    				pre->next = NULL;//这里也要注意,如果我们查找的节点是最后一个节点,我们要将next指向NULL,不然之后遍历时会出问题
    			}
    			q = h->next;//这里需要注意,q应该始终指向改变了的首节点,之前我在定义时去指定,会出现bug
    			while (q) {//进行排序
    				if (t->freq >= q->freq) {//当找到的节点的freq大于等于当前遍历节点时,插入
    					t->next = q;
    					q->pre = t;
    					preQ->next = t;
    					t->pre = preQ;
    					break;
    				}
    				preQ = q;
    				q = q->next;
    			}
    			break;
    		}
    		pre = p;
    		p = p->next;
    	}
    	if (!flag) {
    		printf("未找到该元素,序列不做改变");
    	}
    }
    int main() {
    	int n, data,num;
    	struct Link *head = (struct Link *)malloc(sizeof(struct Link));
    	head->next = NULL;
    	head->pre = NULL;
    	struct Link *p = head;
    	printf("请输入节点个数:n=");
    	scanf("%d", &n);
    	for (int i = 0; i < n; i++) {
    		printf("请输入第%d个节点值:", i + 1);
    		scanf("%d", &data);
    		struct Link *newP = (struct Link*)malloc(sizeof(struct Link));
    		newP->data = data;
    		newP->pre = p;
    		newP->freq = 0;
    		p->next = newP;
    		p = newP;
    	}
    	p->next = NULL;
    	do {
    		printf("请输入要查找的值,输入9999代表结束:num=");
    		scanf("%d",&num);
    		if (num == 9999)continue;//如果num=9999,跳入下一次循环
    		locate(head,num);
    		//p = head->next;
    		printf("调整后链表为:\n");
    		while (p) {
    			printf("%d ",p->data);
    			p = p->next;
    		}
    	} while (num!=9999);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    寻找倒数第K个元素-2009

    /*
    	有一个带头结点的单链表,设计一个函数找到指定的倒数第k个节点,输出节点值,并返回1,否则返回0,前提不能改变链表,尽可能高效
    
    	分析:
    		我们可以先统计出总共的节点数count,那么该节点的顺序数num=count-k+1,当然如果k>count,直接返回0,时间复杂度为O(n)
    		这里还有另一种更加便捷的方法,只需对链表遍历一次,我们设立两个指针,最开始均指向首节点,然后让q先移动k个节点,之后p
    		q同步移动,当q为NULL时,p所在的位置便是倒数第k个节点的位置
    */
    struct Link {
    	int data;
    	struct Link *next;
    };
    #define _CRT_SECURE_NO_WARNINGS
    #include 
    int findTheReciprocalK(Link *h,int k) {//这是第一种解法
    	struct Link *p = h->next;
    	int count = 0,num;
    	while (p) {//统计元素个数
    		count++;
    		p = p->next;
    	}
    	p = h->next;
    	if (k > count) {
    		return 0;
    	}
    	else {
    		num = count - k + 1;
    		while (--num) {//这里要用--num,如果用num--,会导致p为下一个元素,注意
    			p = p->next;
    		}
    		printf("%d",p->data);
    		return 1;
    	}
    }
    int findTheReciprocalK2(Link *h,int k) {//这是第二种解法
    	struct Link *p = h->next, *q = h->next;
    	int count = k;
    	while (count--) {
    		if (q==NULL) {
    			printf("倒数第%d个节点不存在",k);
    			return 0;
    		}
    		q = q->next;
    	}
    	while (q!=NULL) {
    		p = p->next;
    		q = q->next;
    	}
    	printf("倒数第%d个节点值为:%d",k,p->data);
    	return 1;
    }
    int main() {
    	int k;
    	struct Link *head;
    	Link *createLink(int);
    	head = createLink(0);
    	printf("请输入要查倒数第几个数:k=");
    	scanf("%d",&k);
    	//findTheReciprocalK(head,k);
    	findTheReciprocalK2(head, k);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    寻找公共后缀-2012

    /*
    	存在这样一种情况,如果两个单词有相同的后缀,那我们可以将后缀作为公共部分存储,比如being和loading,其中ing就可以作为
    	公共部分,现在存在两个链表,含有公共部分,设计一个高效算法找到其公共后缀其实位置。
    	分析:
    		我们可以这样想,如果我们单纯的让两条链表的指针同步移动,那么只有两条链表长度相同时才可能在公共部分的起始位置相遇,
    		所以我们应该让他们处于同一起跑线上,故而我们应该让较长的链表先走,具体走多少,应该是走过两条链表的长度之差。
    
    */
    struct Link {
    	union 
    	{
    		int data;
    		char letter;
    
    	};
    	Link *next;
    };
    #include 
    #include 
    Link *findCommonSuffix(Link *h1,Link *h2) {
    	struct Link *p = h1->next, *q = h2->next;
    	int countP =0, countQ = 0,gap;
    	while (p) {//遍历,获取链表长度
    		countP++;
    		p = p->next;
    	}
    	while (q) {
    		countQ++;
    		q = q->next;
    	}
    	if (countQ>countP) {//让p指针始终指向较长的那条链表
    		p = h2->next;
    		q = h1->next;
    		gap = countQ - countP;
    	}
    	else {
    		p = h1->next;
    		q = h2->next;
    		gap = countP - countQ;
    	}
    	while (gap--) p = p->next;//长链表指针先行移动gap位
    	while (q != p && q != NULL) {//当两指针不同或不为NULL时继续向后移动
    		q = q->next;
    		p = p->next;
    	}
    	return p;
    	
    }
    int main() {
    	struct Link *h1,*h2,*com,*p1,*p2,*start;
    	Link *createLink(int);
    	char p[] = "letter";//数据类型,char
    	h1 = createLink(1);
    	h2 = createLink(1);
    	com = createLink(1);//公共部分
    	p1 = h1->next;
    	p2 = h2->next;
    	while (p1->next)p1 = p1->next;//到达链尾
    	while (p2->next)p2 = p2->next;
    	p1->next = com->next;//链接公共部分
    	p2->next = com->next;
    	p1 = h1->next;
    	p2 = h2->next;
    	while (p1) {
    		printf("%c",p1->letter);
    		p1 = p1->next;
    
    	}
    	printf("\n");
    	while (p2) {
    		printf("%c",p2->letter);
    		p2 = p2->next;
    
    	}
    	printf("\n");
    	start=findCommonSuffix(h1,h2);
    	printf("%c",start->letter);
    	return  0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    删除绝对值相等的元素-2015

    /*
    	用单链表保存m个整数,节点的结构为[data][next],且|data|<=n。现要求设计一个时间复杂度尽可能高效算法,
    	对于链表中绝对值相等的节点,仅保留第一次出现的节点而删除其余绝对值相等的节点。
    	分析:
    		题目中提到时间复杂度尽可能高效,其本上就是暗示我们采用空间换时间的方式。因为数据是小于等于n的,我们可以开辟一块
    		大小为n的数组,初始值为0,之后我们遍历链表,节点值既是我们寻找的下标,如果下标所在的数组值为0,则将值变为1,如果
    		数组值已经为1,则说明在此之前我们遇见过绝对值相同的元素,故将此节点删除。
    */
    struct Link {
    	union {
    		int data;
    	}type;
    	struct Link *next;
    };
    #include 
    #include 
    #include 
    void deleteRepAbs(Link *h,int n) {
    	int *arr = (int *)malloc(sizeof(int)*n);//这里记住大小是sizeof(int)*n,如果只写n是不对的
    	for (int i = 0; i < n;i++) {//赋初值0
    		*(arr + i) = 0;
    	}
    	struct Link *pre = h, *p = h->next, *r;
    	while (p) {
    		if (*(arr+abs(p->type.data))==0) {//首次访问,作上记录
    			*(arr + abs(p->type.data)) = 1;
    			pre = p;
    			p = p->next;
    		}
    		else {
    			r = p->next;
    			pre->next = p->next;//删除
    			free(p);//释放
    			p = r;
    		}
    	}
    }
    int main() {
    	struct Link *head,*p;
    	int n = 100;//我们这里默许创建的链表里的节点值的绝对值<=100
    	Link *createLink(int);
    	head = createLink(0);//0代表我要创建的链表值类型为int
    	deleteRepAbs(head,n);
    	p = head->next;
    	printf("去重后链表为:");
    	while (p) {
    		printf("%d ",p->type.data);
    		p = p->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    寻找环的入口

    /*
    	设计一个算法判断一个链表是否有环
    	分析:我们可以想象一下,在一个有环的赛道上,有两个人跑步,一个人跑得快,一个人跑得慢,试想,时间充足的情况下,跑得快
    	的那个人是不是会再次遇到跑的慢的人呢?所以对于这道题,我们也可以通过快慢指针来处理,p指针一次移动两个节点,q指针一次移动
    	一个节点,如果他们再次相遇了,说明链表有环,如果p指针为NULL了,说明无环。同时我们需要记录p、q各走的步数,用以确定
    	环的入口点
    */
    struct Link {
    	union {
    		int data;
    	}type;
    	struct Link *next;
    };
    #include 
    Link *isLoop(Link *h) {
    	struct Link *fast = h, *slow = h;
    	while (slow&&fast&&fast->next) {
    		slow = slow->next;
    		fast = fast->next->next;
    		if (slow == fast) {//再次相遇,说明有环
    			break;
    		}
    	}
    	if (slow==NULL||fast==NULL||fast->next==NULL) {
    		return NULL;
    	}
    	fast = h;
    	while (fast != slow) {
    		fast = fast->next;
    		slow = slow->next;
    	}
    	return fast;
    }
    int main() {
    	struct Link *head,*l,*s;
    	int count = 0;
    	Link *createLink(int);
    	head = createLink(0);
    	l = head;
    	while (l->next) {
    		l = l->next;
    	}
    	l->next = head->next->next->next;//手动设置一个环
    	s=isLoop(head);
    	if (s) {
    		printf("链表环起始节点值为:%d",s->type.data);
    	}
    	else {
    		printf("该链表无环");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    就地穿插单链表节点-2019

    /*
    	设线性表L=(a1,a2,a3,...,an-2,an-1,an),采用带头结点的单链表保存,设计一个空间复杂度为O(1)的
    	算法,得到L'=(a1,an,a2,an-1,a3,an-2...)
    	分析:
    		这道题还是有一点复杂的,不过我们慢慢分析它。我们可以这样来操作,我们设置两个指针slow和fast,其中fast每次走两步,
    		slow每次走一步,当fast到达链尾时,slow刚好处于链表中间节点,之前我们学过链表逆置,接下来我们把slow后面的节点逆置,
    		链表就变成了(a1,a2,a3,...,an,an-1,an-2,...),然后我们从中间开始遍历,依次将节点插入到前面节点后面,即可完成要求
    */
    struct Link {
    	union {
    		int data;
    	}type;
    	struct Link *next;
    };
    #include 
    #include 
    void crossTheLink(Link *h) {
    	void reverse(Link *);
    	struct Link *fast = h->next, *slow = h->next,*mid;
    	mid = (struct Link*)malloc(sizeof(struct Link));
    	while (fast->next&&fast->next->next) {//寻找中间节点
    		fast = fast->next->next;
    		slow = slow->next;
    	}
    	mid->next = slow->next;
    	reverse(mid);//逆转mid后面的节点
    	//slow->next = mid->next;
    	fast = h->next;
    	slow->next = NULL;
    	slow = mid->next;
    	while (slow) {//逐个进行插入
    		mid = slow->next;
    		slow->next = fast->next;
    		fast->next = slow;
    		slow = mid;
    		fast = fast->next->next;//因为将slow插入了,所以之前的fast下一个是现在的下两个
    	}
    }
    void reverse(Link *h) {//头插法逆置
    	struct Link *p = h->next,*r;
    	h->next = NULL;
    	while (p) {
    		r = p->next;
    		p->next = h->next;
    		h->next = p;
    		p = r;
    	}
    	
    }
    int main() {
    	struct Link *head,*p;
    	Link *createLink(int);
    	head = createLink(0);
    	crossTheLink(head);
    	printf("交叉后的链表为:");
    	p = head->next;
    	while (p) {
    		printf("%d ", p->type.data);
    		p = p->next;
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    QStringListModel
    java计算机毕业设计空闲教室查询系统MyBatis+系统+LW文档+源码+调试部署
    C语言十六弹 --求两个整数二进制位不同的位数
    LIinux服务器之间如何传输文件
    砖家预测:腾讯云双11服务器优惠价格表(新鲜出炉)
    vue组件
    什么是伪共享?Java8如何使用@sun.misc.Contended避免伪共享?
    云安全—kubelet攻击面
    什么是SSL/TLS/HTTPS,对称非对称加密+证书+CA
    JVM - 运行时数据区
  • 原文地址:https://blog.csdn.net/u014297502/article/details/126105387