线性表

/*
    删除:
    1.删除线性表中元素为X的值	
    2.将顺序表中所有元素偶数元素放到奇数元素之前(14)
    3.去掉有序线性表中相同元素(16)	
    反转交换:	
    4. 反转线性表	
    5. 循环左移线性表n个元素	
    合并:	
    6. 合并两个升序线性表(03)
    7. 求两个线性表的集合元素的并集。
    思维拓展(要求最佳性能)	
    8. 找出顺序表中出现次数大于一半的元素	
    9. 找出有共同后缀的两条单链表中第一个公共结点	
    10. 判断链表是否有环	
*/
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;

typedef int ElemType;	// 给int类型起了别名ElemType 

struct SeqList{	// 顺序表
	ElemType* data;		// 数据域
	int length;			// 表长
	int size;			// 数据域能保存的大小
	
	SeqList(int size) {	// 构造函数,数据初始化 
		data = (ElemType*)malloc(size*sizeof(ElemType));	// 动态分配空间 
		length = 0;
		this->size = size; 
	}	 
};

struct LNode {		// 单链表节点 
	ElemType data;		// 数据域
	LNode* next;		// 指针域,指向下一个元素 
	
	LNode(ElemType d) {
		data = d;
		next = NULL;
	} 
};
typedef LNode* LinkList;	// 将节点指针重命名 

LinkList createLinkList(ElemType arr[], int n) {
// 将数组arr中n个元素构成单链表
	LinkList L = (LNode*)malloc(sizeof(LNode));		// 头节点
	L->next = NULL; 
	LinkList r = L;		// 位指针
	for(int i=0; i<n; ++i) {
		LNode* p = (LNode*)malloc(sizeof(LNode));	// 开辟一个节点
		p->data = arr[i];		// 将数组中的元素赋值给节点p 
		p->next = NULL;	
		r->next = p;			// 用尾插法将节点p插入L 
		r = p; 
	} 
	return L;
} 

SeqList createSeqList(ElemType* arr, int n) {
	SeqList L(2*n);
	for(int i=0; i<n; i++) {
		L.data[i] = arr[i];
	}
	L.length = n;
	return L;
}

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

void show(SeqList L) {
// 输出顺序表L中所有元素
	for(int i=0; i<L.length; ++i) {
		printf("%d ", L.data[i]);
	}
	printf("\n");
}

//1.删除线性表中元素为X的值
void deleteX(LinkList L, ElemType x) {
// 删除单链表L中元素为X的节点
	LNode* p = L;	// 扫描指针
	while(p->next != NULL) {
		if(p->next->data == x) {	// 找到了x元素 
			LNode* q = p->next; 	// 先指向x元素 
			p->next = q->next;		// 删除x元素 
			free(q);				// 释放x元素空间 
		} else {	// 扫描下一个 
			p = p->next;	
		}	
	} 	
}

void deleteX(SeqList& L, ElemType x) {
// 删除顺序表中的元素x
	int i = 0, j = 0; 	// i是扫描指针,将需要保留的元素放在[0,j)区间里面
	for(; i< L.length; ++i) {
		if(L.data[i] != x) {	// 需要保留的元素前移动到j上 
			L.data[j++] = L.data[i];	 
		}
	} 
	L.length = j;
}

void preOdd(SeqList& L) {
// 2.将顺序表L中所有元素偶数元素放到奇数元素之前(14)	
	int i = 0, j = 0; 	// i是扫描指针,将需要保留的元素放在[0,j)区间里面
	for(; i< L.length; ++i) {
		if(L.data[i]%2==0) {				// 将偶数元素前移动到j上 
			swap(L.data[j], L.data[i]);		// 交换元素i和元素就 
			j++;	 
		}
	} 
}
// 3.	去掉有序线性表中相同元素
// 相同元素在有序表中必然是相邻,在删除x中是判断每个元素否则(不)等于x,这里改为判断相邻元素释放相等。
// 留给大家实现
void deleteSame(SeqList& L) {
// 删除升序顺序表L中相同的元素	
	int j = 0;					// 将保留元素放在[0, j] 
	for(int i=1; i<L.length; i++) {
		if(L.data[j] != L.data[i]) {	// 发现相邻不一样的元素 
			L.data[++j] = L.data[i];
		}
	} 
	L.length = j+1;
}

void deleteSame(LinkList L) {
// 删除升序顺序表L中相同的元素	
	LNode* p = L->next;	// 扫描指针 
	while(p && p->next) {
		if(p->next->data == p->data) {	// 要删除的结点 
			LNode* q = p->next;
			p->next = q->next;	// 删除了q结点(链表上) 
			free(q);			// 释放其空间 
		} else {	// 否则p往后检查 
			p = p->next;
		}
	}
}

void reverse(SeqList& L) {
	for(int i=0, j=L.length-1; i<j; i++,j--) {	// i从前往后,j从后往前扫描,直到相遇 
		swap(L.data[i], L.data[j]);		// 交换第i个和第j个(倒数第i个)元素 
	}
} 

void reverse(LinkList L) {
// 翻转单链表
	LNode* p = L->next;	// 扫描指针
	L->next = NULL;		// 取出头节点
	while(p != NULL) {
		LNode* q = p->next;	// 保存p的后继节点
		p->next = L->next;	// 用头插法插入L链表 
		L->next = p; 
		p = q;				// p指针后移 
	} 
}
void reverse2(LinkList L) {
//反转顺序表L ,和reverse功能一样,借助了三个指针分别来指向当前扫描节点和其前驱、后继 
	LNode* p = L->next;
	LNode* r = NULL;	// 在原链表中p的前驱
	LNode* q;	// 在原链表中p的后继
	while(p) {
		q = p->next;	// 先保存p的后继,防止断链表
		p->next = r;	// 反转链表 
		r = p;			// 往后移动 
		p = q;
	}  
	L->next = r;		// 最后一个结点成为第一个结点 
}

void reverse(SeqList& L, int l, int h) {
// 翻转L[l, h)中的元素 
	for(int i=l, j=h-1; i<j; i++,j--) {	// i从前往后,j从后往前扫描,直到相遇 
		swap(L.data[i], L.data[j]);		// 交换第i个和第j个(倒数第i个)元素 
	}
} 

void reLeftShift(SeqList L, int n) {
	n = n % L.length;			// 循环左移length个元素就和原来一样了 
	reverse(L, 0, L.length);	// 全部翻转 
	reverse(L, 0, n);			// 翻转前n个部分 
	reverse(L, n, L.length); 	// 翻转后面元素 
}

int getLength(LinkList L) {
// 得到单链表L的长度 
	int len = 0;
	LNode* p = L->next; 
	while(p) {
		p = p->next;
		len++;
	}
	return len;
}

void ReLeftShift(LinkList L, int n) {
// 循环左移n个元素
	int len = getLength(L);	// 单链表长度 
	n = n % len;	// 因为循环左移length个元素就相对于没移动 
	LNode* p = L;	// 第n个结点的前驱 
	for(int i=0; i<len-n; i++) p = p->next;
	LNode* q = p;	// 尾指针 
	while(q->next) q = q->next;
	q->next = L->next;	// 这三句话的顺序建议在纸上画一下,保证不断链接 
	L->next = p->next;
	p->next = NULL;
} 
// 6.  合并两个升序线性表(03)
SeqList merge(SeqList L1, SeqList L2) {
// 归并两个升序线性表L1,和L2并放回结果 
	SeqList L(L1.length+L2.length);
	int i = 0, j = 0;	// 扫描L1和L2的指针
	int k = 0;	// 已经归并好的元素个数 
	while(i<L1.length || j<L2.length) {	// L1或者L2中还有元素没有归并 
		if(j>=L2.length || i<L1.length && L1.data[i] <= L2.data[j]) {	// 拿取L1首元素情况:L2已经拿完或者L1没有拿完并且L1首元素比L2首元素小 
			L.data[k++] = L1.data[i++];
		} else {
			L.data[k++] = L2.data[j++];
		} 
	}
	L.length = k;	// 修改L的长度 
	return L; 
}	

void merge(LinkList L1, LinkList L2) {
// 归并两个升序单链表L1,和L2将结果保存在L1中 
	LNode* p = L1->next, *q = L2->next;
	LNode* r = L1;	// 合并以后的链表尾部 
	while(p&&q) {
		if(p->data <= q->data) {	// 比较p和q的值,将较小的尾插到r后面 
			r->next = p;	// 尾插法插入 
			r = p;			// 修改为指针 
			p = p->next;	 
		} else {
			r->next = q;
			r = q;
			q = q->next;
		} 
	} 
	if(p) r->next = p;	// 将剩余的元素全部插入r后面 
	else r->next = q;
}

// 7. 求两个线性表的集合元素的并集。
void Union(SeqList& L1, SeqList L2) {
// 求顺序表L1和L2的并集,放入L1中
	for(int i=0; i<L2.length; i++) {	// 遍历L2中的每一个元素
		bool ok = false;				// 标记L2的第i个元素是否在L1中
		for(int j=0; j<L1.length; j++) {	// 查找L1的第i个元素是否在L2中
			if(L1.data[j]==L2.data[i]) {	// 找到
				ok = true;		
				break;
			}
		}
		if(!ok) {	// 如果不在L1中,即是并集中的元素
			L1.data[L1.length++] = L2.data[i];
		}
	}
}
int Union(LinkList A, LinkList B){
//遍历A的每一个元素,若它存在于B中,则从B中删除,反之不处理
	LNode *p = A;
	for(; p->next!=NULL; p = p->next){		// 遍历A 
		for(LNode *q = B; q->next!=NULL; q = q->next){	// 遍历B 
			if(p->next->data==q->next->data){	// A中元素在B中 
				LNode* d = q->next;	// 将B中的元素删除 
				q->next = d->next;					
				free(d);
			}
		}
	}
	//最后把改变过的B加到A末尾
	p->next=B->next;
}
// 思考交集、差集如何求  

// 8. 找出顺序表中出现次数大于一半的元素	
ElemType major(SeqList L) {
// 找出线性表L中出现次数大于一半的元素,找到返回元素,没有返回-1
	ElemType m = L.data[0];		// m为出现次数大于一半的元素,初始时默认为第一个元素
	int cnt = 1;				// cnt为最多元素出现次数减去其他元素出现次数
	for(int i=1; i<L.length; i++) {	// 扫描表中剩余元素
		if(L.data[i] != m) {		// 如果不等于m,cnt减一
			cnt--;			
			if(cnt==0) {		// 如果为0了,则m不可能是出现次数大于一半的元素
				m = L.data[i];	// 更新m值
				cnt = 1;		// 更新cnt
			}
		} else {				// 如果和m相等,则出现次数加一
			cnt++;
		}
	}
	cnt = 0;					// 统计m在L中出现次数
	for(int i=0; i<L.length; i++) {	
		if(L.data[i]==m) cnt++;
	}
	if(cnt>=(L.length+1)/2) return m;	// 超过一半则返回m
	else return -1;					// 否则返回-1
}


// 9. 找出有共同后缀的两条单链表中第一个公共结点
LNode* searchFirstCommon(LinkList L1, LinkList L2) {
// 找出有共同后缀的两条单链表L1,L2中第一个公共结点并返回
	int len1 = getLength(L1), len2=getLength(L2);	// 计算两个链表的表长
	LNode* p = L1->next, *q = L2->next;				// L1和L2的扫描指针
	while(len1!=len2) {								// 当前两个表长不一样
		if(len1>len2) 	{p=p->next; len1--;}		// 将长度那个往后移动
		else 			{q=q->next; len2--;}
	}
	while(p!=NULL && p!=q) {		// 扫描到最后前没有找到公共结点
		p=p->next;	q = q->next;	// 两个表同时往后扫描
	}		
	return p;						// 返回公共结点
}

// 10. 判断链表是否有环	
bool isExistLoop(LinkList  L) {
// 判断带头结点链表中是否存在环
    LNode *fast,*low;		// 快慢指针扫描
    fast=low=L;		
    while(fast!=NULL&&low!=NULL&&fast->next!=NULL) {	
        fast=fast->next->next;		// 快指针一次走两步
        low=low->next;				// 慢指针一次走一步
        if(fast==low)				// 如果碰头则存在环
           return true;
    }
    return false;					// 否则不存在
}
 
int main() {
	int arr1[] = {1,2,2,7,5};
	int arr2[] = {4,5};
	LinkList L1 = createLinkList(arr1, sizeof(arr1)/sizeof(arr1[0]));
	LinkList L2 = createLinkList(arr2, sizeof(arr2)/sizeof(arr2[0]));
	L1->next->next->next->next->next = L1->next->next;
	bool isLoop = isExistLoop(L1);
	printf("%d", isLoop);
	return 0;
}
 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值