数据结构 有序表

有序表就是表中的数据元素按照非递减或者非递增的规律进行排列。有序表的基本操作和线性表大致相同,并且有序表也可以有顺序表和链表两种存储表示方法。

在顺序有序表中进行插入操作 插入后仍保持其有序性

首先定义变量 i,令其值等于表尾数据的下标,使其从表尾开始遍历。进入循环,while (i >= 0 && x < L.elem[i]);在循环之中将数据右移一位同时 i--; 跳出循环的两种情况: 一:i=-1,此时直接将x插入到表头,二:x>=L.elem[i], 此时将x赋值给 L.elelm[i] 的后一个元素,最后表长加一

本题建立的是有序的顺序表

#include<stdio.h>
const int LIST_INIT_SIZE = 100;
const int LISTINCREMENT = 10;
typedef struct {
	int *elem;
	int length;
	int listsize;
	int listincrementsize;
}SqList;

void InitList_Sq(SqList &L,int maxsize=LIST_INIT_SIZE,int incresize=LISTINCREMENT)
{
	L.elem = new int[maxsize];
	L.length = 0;
	L.listsize = maxsize;
	L.listincrementsize = incresize;
}

void OrdInsert_Sq(SqList &L, int x)
{
	//在顺序表L中插入元素x,并且插入后仍满足有序   该有序表的数据时非递减的
	int i = L.length - 1;      //遍历有序顺序表时 从表为开始遍历
	while (i >= 0 && x < L.elem[i])      
	{
		L.elem[i + 1] = L.elem[i];   //值大于x的元素后移
		i--;
	}
	L.elem[i + 1] = x;  //跳出循环的两种情况 一:i=-1,此时直接将x插入到表头,二:x>=L.elem[i],此时将x赋值给L.elelm[i]的后一个元素
	L.length++;
}

void main()
{
	int i;
	int x = 6;
	SqList L;
	InitList_Sq(L);
	for (i = 0; i < 10; i++)
	{
		L.elem[i] = i + 1;
		L.length++;
	}
	printf("表内容为:");
	for (i = 0; i < 10; i++)
		printf("%d ", L.elem[i]);
	printf("\n");
	OrdInsert_Sq(L, x);
	printf("在有序表中插入数据6后表为:");
	for (i = 0; i < 11; i++)
		printf("%d ", L.elem[i]);

}

以有序表为集合 将B表中不同的元素提取到A表之中

本题思路是定义两个循环变量,从表L的前两个数据元素开始进行向后遍历。对于i,j,最初如果a[i]=a[j], 则j++,i 的值不变。然后再比较a[i] 和 a[j] 的值。如果不相等,就把 a[j] 插入到 a[i] 的后面。如果相等,则继续保持 i 的值不变,j 的值加一。一直循环就会通过覆盖,将L表中不同的元素都赶到表的前面部分。此时j=L.length 遍历到表的末尾,则跳出循环,结束。

本算法本质是将不同的元素通过向前一位覆盖的办法,完成不同元素与相同元素的分开,然后通过表长控制,去除掉多余的数据元素。即原地算法,也叫inplace算法。

本题建立的是有序的顺序表

#include<stdio.h>
const int LIST_INIT_SIZE = 100;
const int LISTINCREMENT = 10;
typedef struct {
	int *elem;
	int length;
	int listsize;
	int listincrementsize;
}SqList;

void InitList_Sq(SqList &L,int maxsize=LIST_INIT_SIZE,int incresize=LISTINCREMENT)
{
	L.elem = new int[maxsize];
	L.length = 0;
	L.listsize = maxsize;
	L.listincrementsize = incresize;
}

void purge_Osq(SqList &L)
{
	//已知L是一个含有相同元素的顺序有序表,删除其中的相同元素
	int i = 0, j = 1;     //定义两个循环变量i,j,令它们最开始指向表L的前两个数据
	while (j < L.length)
	{
		if (L.elem[i]!= L.elem[j])  
		{
			L.elem[i + 1] = L.elem[j];  //将L.elem[j]插入到L.elem[i]之后
			i++;           //继续查找下一个元素
		}
		j++;
	}
	L.length = i + 1;
}

void main()
{
	int i;
	int x = 6;
	SqList L;
	int a[12] = { 1,2,3,4,4,5,6,7,7,8,9,10 };
	InitList_Sq(L);
	for (i = 0; i < 12; i++)
	{
		L.elem[i] = a[i];
		L.length++;
	}
	printf("表内容为:");
	for (i = 0; i < 12; i++)
		printf("%d ", L.elem[i]);
	printf("\n");
	purge_Osq(L);
	printf("经过删除表L内容为:");
	for (i = 0; i < L.length; i++)
		printf("%d ", L.elem[i]);
	

}

 对于两个带头结点的单向循环有序链表A和B 求其对应集合的并集

定义三个指针pa,pb,rc。pa,pb指向集合A和B对应链表的结点,rc指向C当前的表尾结点。然后比较pa和pb所指结点的元素,如果pa->data < pb->data,说明pa所指的数据在B表中不可能出现,则应该将pa结点链接到C链表中(rc->next=pa),如果pa->data > pb->data,说明pb所指的数据在A表中不可能存在,所以将pb结点链接到C链表中 (rc->next=pb),如果pa->data = pb->data,则其中任意结点链接到C表中,并释放另一结点空间,直到有一个表被接入完,再接入另一个表的剩余段。

本题建立的是带有头结点的单向循环有序链表

#include<stdio.h>

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

LinkList pHeada;
LinkList pHeadb;
void CreateList_L(LinkList &pHead, int a[], int n)
{
	int i;
	LinkList L;
	pHead = new LNode;
	pHead->data = NULL;      //建立头结点
	pHead->next = pHead;       //头结点的后继指针指向自己
	L = pHead;                  //全局变量L,用于标记链表开头
	LNode *s;    //用于新建结点


	for (i = 0; i < n; i++)
	{
		s = new LNode;
		s->data = a[i];
		pHead->next = s;           //将新建的结点接在头结点的后面
		s->next = L;              //将新建结点的后继指针指向表头 形成循环
		pHead = s;              //移动头指针pHead 将其指向新建结点
	}
}

void union_OL(LinkList &La, LinkList &Lb)
{
	//La和Lb分别为表示集合A和集合B的循环链表的头指针,求这两个集合的并集
	//操作完成后La表示集合C的循环链表的头指针,集合A,B的循环链表都不复存在
	LNode *pa, *pb, *rc, *qb,*pp;   //pa和pb用于指向A表和B表,rc指向新表的当前结点,qb用于删除多余的结点,pp用于找到最初A表头结点的位置,便于后面形成循环
	pa = La->next->next;  //La指向的是表中的最后一个元素,所以pa指向的是第一个元素
	pb = Lb->next->next;
	rc = La->next;		//rc指向的是表中的头结点
	pp = rc;

	while (pa != La->next&&pb != Lb->next)
	{
		if (pa->data < pb->data)         //pa所指的数据更小,所以把pa接在rc的后面
		{
			rc->next = pa;
			rc = pa;
			pa = pa->next;
		}
		else if (pa->data > pb->data)    //pb所指的数据更小,所以把pb接在rc的后面
		{
			rc->next = pb;
			rc = pb;
			pb = pb->next;
		}
		else                         //pa和pb所指的元素大小相等,将pa指向rc的后面,删除bp所指的结点
		{
			rc->next = pa;
			rc = pa;
			pa = pa->next;
			qb = pb;               //引入qb指向待删除的结点,防止pb后移后结点丢失
			pb = pb->next;
			delete qb;
		}
	}
	if (pb == Lb->next)     //链接A的剩余段
	{
		rc->next = pa;
	}
	else                     //链接B的剩余段
	{
		rc->next = pb;
		pb = Lb->next;       //pb指向B的头结点
		Lb->next = pp;
		La = Lb;              //构成C的循环链
	}
	delete pb; //释放B表的表头
}

void main()
{
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int b[10] = { 4,5,6,7,8,9,11,22,33,44 };
	LNode *p;
	CreateList_L(pHeada, a, 10);
	printf("输出A集合:");
	for (p = pHeada->next->next; p != pHeada->next; p = p->next)
		printf("%d ", p->data);
	printf("\n");
	CreateList_L(pHeadb, b, 10);
	printf("输出B集合:");
	for (p = pHeadb->next->next; p != pHeadb->next; p = p->next)
		printf("%d ", p->data);
	printf("\n");
	union_OL(pHeada, pHeadb);
	printf("输出A和B的并集为:");
	for (p = pHeada->next->next; p != pHeada->next; p = p->next)
		printf("%d ", p->data);
} 

判断两个用有序表表示的集合是否相等

本题算法较为简单,首先要定义两个指针,分别指向各自链表的第一个结点(头结点之后的那个结点),然后控制其相等的条件,再此条件下使其遍历结束,并且输出TRUE,否则不符合条件的输出FALSE.

本题建立的链表为带有头结点的单向有序链表

#include<stdio.h>
#define TRUE 1
#define FALSE 0
typedef struct LNode {
	int data;
	struct LNode *next;
}LNode, *LinkList;

void CreateList_L(LinkList &L, int a[], int n)
{
	int i;
	LNode *s;
	L = NULL;     //创建链表时一定不要忘记此处要让L=NULL!!!
	for (i = n - 1; i >= 0; i--)
	{
		s = new LNode;
		s->data = a[i];
		s->next = L;    //逆序创建时第一个结点是整个链表的尾节点,此时第一次是给其next指针赋值为NULL,第二次开始才是指向L所指结点
		L = s;
	}
	s = new LNode;
	s->data = NULL;
	s->next = L;
	L = s;
}

bool isequal_OL(LinkList A, LinkList B)
{
	//指针A和B分别指向两个带头结点的单链表
	//若两集合相同,则返回TRUE,否则返回FALSE
	LNode *pa, *pb;
	pa = A->next;    //A和B都是指向头结点
	pb = B->next;
	while (pa&&pb&&pa->data == pb->data)
	{
		pa = pa->next;
		pb = pb->next;
	}
	if (pa == NULL && pb == NULL)
		return TRUE;
	else
		return FALSE;
}

void main()
{
	LinkList La, Lb;
	LNode *p;
	int a[5] = { 1,2,3,4,5 };
	int b[5] = { 1,2,3,4,5 };
	CreateList_L(La, a, 5);
	CreateList_L(Lb, b, 5);
	if (isequal_OL(La, Lb) == 1)
		printf("这两个集合相等。");
	else
		printf("这两个集合不相等。");
}

本笔记所依据的教材为严薇敏版的《数据结构及应用算法教程》

所有代码在Visual Studio 2017上均可正常运行

如有错误欢迎指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值