线性表

1.free()

  • free只能释放由malloc开辟的内存
  • PNode pHead=(PNode)malloc(sizeof(Node));
    pHead = NULL;
    free(pHead)
    可以释放空指针,If null, free call will do noting。

2.好像没什么好方法判断内存是否被释放?

3.时间复杂度

表示级数,常见的

O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)

没有什么O(1/2n^2),前面的系数都去掉。

for (int i = 0; i < n; i++)
{
	for (int j = i; j < n; j++)
	{

	}
}

像这种,时间复杂度都是O(N^2)。

有平均时间复杂度和最坏时间复杂度,一般默认都是最坏时间复杂度。

线性表顺序存储结构插入一个元素平均移动次数:n/2

线性表顺序存储结构删除一个元素平均移动次数:(n-1)/2。

注意区别。

 

一、线性表

 

线性表的动态分配顺序存储结构

//线性表顺序存储结构(动态分配),感觉和静态分配没有毛线区别。
#include<stdio.h>

#define true 1
#define false 0
typedef int bool;

#define LISTSIZE  20

typedef struct SequenceList
{
	int *data;
	int length;//线性表已存储元素个数
	int listsize;//线性表分配的空间大小
}SqList;


//初始化线性表
bool InitList(SqList *s)
{
	s->data = (int *)malloc(sizeof(int)*LISTSIZE);
	if (!s->data)
	{
		exit(-1);
	}
	s->length = 0;
	s->listsize = LISTSIZE;
	return 1;
}


//求线性表长度
int ListLength(SqList *s)
{
	return s->length;
}

//判断线性表是否为空,是返回1,不是返回0
bool ListEmpty(SqList *s)
{
	return s->length == 0;
}

//遍历线性表
void ListTraverse(SqList *s)
{
	for (int i = 0; i < s->length; i++)
	{
		printf("%d ", s->data[i]);
	}
	printf("\n");
}


//插入操作,插入一个元素到线性表的第i个位置
//1.判断线性表是否已满
//2.判断i的位置是否合理
//3.从最后一个元素到当前元素后移
//4.当前元素插入

bool ListInsert(SqList *s,int i,int val)
{
	if (s->length == s->listsize)
		return false;//满了
	if (i<1 || i>s->length + 1)
		return false;//插入位置不合理
	if (i <= s->length)
	{
		for (int k = s->length - 1; k >= i - 1; k--)
		{
			s->data[k + 1] = s->data[k];
		}
	}
	s->data[i - 1] = val;
	s->length++;
	return true;
}


//删除第i个元素,用val存储
//1.判断线性表是否为空
//2.判断删除的位置是否合理
//3.存储删除的值
//从删除位置开始到结尾向前左移
bool ListDelete(SqList *s, int i, int *val)
{
	if (s->data == 0)
		return false;
	if (i<1 || i>s->length)
		return false;
	*val = s->data[i - 1];
	for (int k = i; k < s->length; k++)
	{
		s->data[k - 1] = s->data[k];
	}
	s->length--;
	return true;
}

//清空线性表
void ListClear(SqList *s)
{
	s->length = 0;
}

//销毁线性表,释放数据域,线性表尺寸和元素个数都置0
void ListDestroy(SqList *s)
{
	free(s->data);
	s->data = NULL;
	s->length = 0;
	s->listsize = 0;
}

//获取线性表第i个元素
bool ListGetElement(SqList *s,int i,int *val)
{
	if (s->length == 0)
		return false;
	if (i > s->length || i < 1)
		return false;
	*val=  s->data[i - 1];
	return true;
}

//判断线性表中是否存在某个元素,如果存在返回第一个满足要求的位置,如果不存在,返回0
int ListLocateElement(SqList *s, int val)
{
	for (int i = 0; i < s->length; i++)
	{
		if (val == s->data[i])
			return i+1;
	}
	return 0;
}

//求线性表并集
void ListUnion(SqList *a, SqList *b)
{
	int a_len = a->length;
	int b_len = b->length;
	for (int i = 0; i < b_len; i++)
	{
		if (!ListLocateElement(a, b->data[i]))
		{
			ListInsert(a, ++a_len, b->data[i]);
		}
	}

}

//冒泡排序
void ListBubble(SqList *s)
{
	for (int i = 0; i < s->length-1; i++)
	{
		for (int j = 0; j < s->length - 1 - i; j++)
		{
			if (s->data[j] > s->data[j + 1])
			{
				int temp = s->data[j];
				s->data[j] = s->data[j + 1];
				s->data[j + 1] = temp;
			}
		}
	}
}

//线性表倒序排列,简单,就是第一个和最后一个交换,第二个和倒数第二个交换
void ListReverse(SqList *s)
{
	for (int i = 0; i < s->length / 2 ; i++)
	{
		int temp = s->data[i];
		s->data[i] = s->data[s->length - i - 1];
		s->data[s->length - i - 1] = temp;
	}
}


int main(void)
{
	SqList s;
	//初始化线性表
	InitList(&s);
	printf("初始化线性表s后,判断线性表是否为空:%d\n", ListEmpty(&s));
	printf("初始化线性表s后,求线性表的长度:%d\n", ListLength(&s));
	//向线性表中插入几个元素
	ListInsert(&s, 1, 1);
	ListInsert(&s, 1, 2);
	ListInsert(&s, 1, 3);
	ListInsert(&s, 1, 4);
	//遍历线性表
	printf("插入元素之后,遍历线性表s:\n");
	ListTraverse(&s);
	//删除第二个元素
	int val;
	ListDelete(&s, 2, &val);
	printf("删除s的第二个元素是:%d\n", val);
	//遍历线性表
	printf("删除s第二个元素之后,线性表为:\n");
	ListTraverse(&s);
	//线性表长度
	printf("线性表s长度为:%d\n", ListLength(&s));
	//再定义一个线性表b
	SqList b;
	InitList(&b);
	ListInsert(&b, 1, 1);
	ListInsert(&b, 1, 5);
	ListInsert(&b, 1, 3);
	ListInsert(&b, 1, 4);
	ListInsert(&b, 5, 7);
	//遍历线性表
	printf("插入元素之后,遍历线性表b:\n");
	ListTraverse(&b);
	ListUnion(&s, &b);
	//s和b的交集,遍历
	printf("求s和b的交集:\n");
	ListTraverse(&s);
	//冒泡排序
	printf("冒泡排序之后,线性表为:\n");
	ListBubble(&s);
	ListTraverse(&s);
	//线性表转置
	ListReverse(&s);
	printf("转置线性表后,线性表为:\n");
	ListTraverse(&s);
	//清空列表s
	ListClear(&s);
	printf("清空列表s之后,判断线性表是否为空:%d\n", ListEmpty(&s));
	return 0;
}

线性表的静态分配顺序存储结构

//线性表的静态分配顺序存储结构
//需要三个元素,1.数组长度,2.线性表长度,3.数据域

#include<stdio.h>

#define true 1
#define false 0
typedef int bool;

#define MAXSIZE 20//定义数组的长度

typedef struct SquenceList
{
	int data[MAXSIZE];
	int listlength;
}SqList;

//初始化线性表
void InitList(SqList *s)
{
	s->listlength = 0;
}

//判断线性表是否为空,空返回1,非空返回0
bool ListEmpty(SqList *s)
{
	return s->listlength == 0;
}

//在第i个位置插入一个元素
//1.判断线性表是否已满
//2.判断插入的位置是否正确
//3.将最后一个元素到插入点之后的元素依次后移
//4.将元素值插入到第i个位置
bool ListInsert(SqList *s, int i,int val)
{
	if (s->listlength == MAXSIZE)
		return false;
	if (i<1 || i>s->listlength + 1)
		return false;
	if (i <= s->listlength)
	{
		for (int k = s->listlength - 1; k >= i-1; k--)
		{
			s->data[k + 1] = s->data[k];
		}
	}
	s->data[i - 1] = val;
	s->listlength++;
	return true;
}

//删除线性表中第i个元素
//1.判断线性表是否为空
//2.判断删除位置是否合理
//3.取出要删除的元素
//4.从删除点到最后一个元素依次向前移动一个
bool ListDelete(SqList *s, int i, int *val)
{
	if (s->listlength == 0)
		return false;
	if (i<1 || i>s->listlength)
		return false;
	*val = s->data[i - 1];
	for (int k = i - 1; k < s->listlength-1; k++)
	{
		s->data[k] = s->data[k + 1];
	}
	s->listlength--;
	return 1;
}

//遍历线性表
void ListTraverse(SqList *s)
{
	for (int i = 0; i < s->listlength; i++)
	{
		printf("%d ", s->data[i]);
	}
	printf("\n");
}

//线性表长度
int ListLength(SqList *s)
{
	return s->listlength;
}

//清空线性表,将线性表长度置为0,数组里面的元素也没法删
void ListClear(SqList *s)
{
	s->listlength = 0;
}

//获取线性表第i个元素值,i指位置
bool ListGetElement(SqList *s, int i, int *val)
{
	if (i<1 || i>s->listlength || s->listlength == 0)
		return false;
	*val = s->data[i - 1];
	return true;
}

//查找线性表中是否存在元素val,如果存在返回第一个满足要求的位置,如果不存在返回0
int ListLocateElement(SqList *s, int val)
{
	for (int i = 0; i < s->listlength; i++)
	{
		if (val == s->data[i])
			return i + 1;
	}
	return 0;
}

//两个线性表并集,这里没有考虑线性表满问题
void ListUnion(SqList *a, SqList *b)
{
	int a_len = a->listlength;
	int b_len = b->listlength;
	int val;
	for (int i = 1; i <= b_len; i++)
	{
		ListGetElement(b, i, &val);
		if (!ListLocateElement(a,val))
		{
			ListInsert(a, ++a_len, val);

		}
	}
}


int main(void)
{
	SqList s;
	//初始化线性表
	InitList(&s);
	printf("初始化线性表s后,判断线性表是否为空:%d\n", ListEmpty(&s));
	printf("初始化线性表s后,求线性表的长度:%d\n", ListLength(&s));
	//向线性表中插入几个元素
	ListInsert(&s, 1, 1);
	ListInsert(&s, 1, 2);
	ListInsert(&s, 1, 3);
	ListInsert(&s, 1, 4);
	//遍历线性表
	printf("插入元素之后,遍历线性表s:\n");
	ListTraverse(&s);
	//删除第二个元素
	int val;
	ListDelete(&s, 2, &val);
	printf("删除s的第二个元素是:%d\n", val);
	//遍历线性表
	printf("删除s第二个元素之后,线性表为:\n");
	ListTraverse(&s);
	//线性表长度
	printf("线性表s长度为:%d\n", ListLength(&s));
	//再定义一个线性表b
	SqList b;
	InitList(&b);
	ListInsert(&b, 1, 1);
	ListInsert(&b, 1, 5);
	ListInsert(&b, 1, 3);
	ListInsert(&b, 1, 4);
	ListInsert(&b, 5, 7);
	//遍历线性表
	printf("插入元素之后,遍历线性表b:\n");
	ListTraverse(&b);
	ListUnion(&s, &b);
	//s和b的交集,遍历
	printf("求s和b的交集:\n");
	ListTraverse(&s);
	//清空列表s
	ListClear(&s);
	printf("清空列表s之后,判断线性表是否为空:%d\n",ListEmpty(&s));
	return 0;
}

单链表

//链表,带头结点
#include<stdio.h>
#include<malloc.h>

#define true 1
#define false 0
typedef int bool;

typedef struct Node
{
	int data;
	struct Node *next;
}Node;

typedef struct Node* PNode;

//初始化链表
bool InitList(PNode *pHead)
{
	*pHead = (PNode)malloc(sizeof(Node));
	if (!(*pHead))//分配空间失败
	{
		return false;
	}

	(*pHead)->next = NULL;
	return true;
}

//第i个位置插入一个链表节点
bool ListInsert(PNode pHead, int i, int val)
{
	int j = 0;
	PNode p = pHead;
	PNode q = (PNode)malloc(sizeof(Node));
	while (p&&j < i - 1)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i-1)
	{
		return false;
	}
	q->data = val;
	q->next = p->next;
	p->next = q;
	return true;

}

//删除第i个位置的节点
bool ListDelete(PNode pHead, int i, int* val)
{
	int j = 0;
	PNode p = pHead;
	while (p->next&&j < i - 1)//注意while(p->pNext!=NULL&&i<pos-1)与while(p!=NULL&&i<pos-1)的差别,比如链表长度为6,当数大于等于8时有区别
	{
		p = p->next;
		j++;
	}
	if (!p->next || j > i-1)
	{
		return false;
	}
	PNode q = p->next;
	*val = q->data;
	p->next = q->next;
	free(q);
	return true;

}

//判断链表是否为空
bool ListEmpty(PNode pHead)
{
	if (pHead->next)
	{
		return false;
	}
	else
	{
		return true;
	}
}

//求链表长度
int ListLength(PNode pHead)
{
	int i = 0;
	PNode p = pHead;
	while (p->next) 
	{
		i++;
		p = p->next;
	}
	return i;

}

//遍历链表
void ListTraverse(PNode pHead)
{
	PNode p = pHead->next;
	while (p)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
}

//获取链表第i个元素的值
bool ListGetElement(PNode pHead, int i, int *val)//val存储返回值
{
	int j = 0;
	PNode p = pHead;
	while (p->next&&j<i-1)
	{
		p = p->next;
		j++;
	}
	if (!p->next || j > i - 1)
	{
		return false;
	}
	*val = p->next->data;
	return true;
}

/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int ListLocateElement(PNode pHead, int val)
{
	PNode p = pHead->next;
	int i = 0;
	while (p)
	{
		i++;
		if (p->data == val)
			return i;
		p = p->next;
	}
	return 0;

}

//链表选择排序
void ListSelectSort(PNode pHead)
{
	PNode p = pHead->next;
	PNode q = p->next;
	int length = ListLength(pHead);
	for (int i = 0; i < length-1; i++)
	{
		for (int j = i + 1; j < length; j++)
		{
			if (p->data > q->data)
			{
				int temp = p->data;
				p->data = q->data;
				q->data = temp;
			}
			q = q->next;
		}
		p = p->next;
		q = p->next;
	}
}

//将链表置为空链表,除了头结点外,其他都释放
void ListClear(PNode pHead)
{
	PNode p = pHead->next;
	PNode q;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	pHead->next = NULL;
}


//销毁链表,头结点也不存在
void ListDestroy(PNode *pHead)
{
	PNode p;
	while (*pHead)
	{
		printf("%d\n", 1);
		p = (*pHead)->next;
		printf("%d\n", 2);
		free(*pHead);
		printf("%d\n", 3);
		*pHead = p;
		printf("%d\n", 4);
	}

}



//创建链表,从头插入
void CreateListHead(PNode pHead)
{
	PNode p = pHead;
	int num, data;
	printf("清输入要创建的节点个数\n");
	scanf("%d", &num);
	for (int i = 0; i < num; i++)
	{
		scanf("%d", &data);
		PNode q = (PNode)malloc(sizeof(Node));
		q->data = data;
		q -> next = p->next;
		p->next = q;
	}
}

//创建链表,从尾插入
void CreateListTail(PNode pHead)
{
	PNode p = pHead;
	int num, data;
	printf("清输入要创建的节点个数\n");
	scanf("%d", &num);
	for (int i = 0; i < num; i++)
	{
		scanf("%d", &data);
		PNode q = (PNode)malloc(sizeof(Node));
		q->data = data;
		p->next = q;
		p = q;
	}
	p->next = NULL;
}

//反转链表
//思路:每次都将原第一个结点之后的那个结点放在新的表头后面。
//比如1, 2, 3, 4, 5
//第一次:把第一个结点1后边的结点2放到新表头后面,变成2, 1, 3, 4, 5
//第二次:把第一个结点1后边的结点3放到新表头后面,变成3, 2, 1, 4, 5
//……
//直到: 第一个结点1,后边没有结点为止。
PNode ListReverse(PNode pHead)
{
	//链表只有头节点,或者只有一个节点
	if (pHead->next == NULL || pHead->next->next == NULL)
	{
		return pHead;
	}
	PNode tail = pHead->next;//第一个节点为尾
	PNode current = tail->next;//current为当前需要调换到前面的节点
	while (current)
	{
		tail->next = current->next;
		current->next = pHead->next;
		pHead->next = current;
		current = tail->next;
	}
	return pHead;
}

//查找链表倒数第K个节点
//方法一:需遍历两次链表;先求链表的长度len,然后遍历len-k的距离即可查找到单链表的倒数第k个节点
//方法二:遍历一次链表,时间复杂度为O(n);设置两个指针p1、p2,让p2先走k-1步,然后p1、p2再同时走,
//        当p2走到链表尾时,p1所指位置就是所要找的节点
PNode ListSearchReverseKthNode(PNode pHead, int k)
{
	if (pHead->next == NULL || k <= 0)
	{
		return NULL;
	}
	PNode p1 = pHead->next;
	PNode p2 = pHead->next;
	while (p2&&--k)
	{
		p2 = p2->next;
	}
	while (p2->next)
	{
		p2 = p2->next;
		p1 = p1->next;
	}
	return p1;


}
int main(void)
{
	
	PNode pHead;
	//初始化链表
	InitList(&pHead);
	//初始化之后判断链表是否为空,求链表长度
	printf("初始化之后链表是否为空:%d\n", ListEmpty(pHead));
	printf("初始化之后链表的长度:%d\n", ListLength(pHead));
	//创建链表,从头插入元素
	CreateListHead(pHead);
	//创建链表,头插法
	ListTraverse(pHead);

	创建链表,尾插法,头插法和尾插法二选一,一起用会影响。
	//CreateListTail(pHead);
	//ListTraverse(pHead);

	//对链表进行排序
	ListSelectSort(pHead);
	//输出排序之后的链表内容
	printf("链表排序:\n");
	ListTraverse(pHead);
	//获取链表第5个元素值
	int val;
	ListGetElement(pHead, 5, &val);
	printf("第五个元素值为:%d\n", val);
	//删除链表第2个元素
	ListDelete(pHead, 2, &val);
	printf("删除第2个元素值后,链表的值为:\n");
	ListTraverse(pHead);
	//链表第二个位置插入100
	ListInsert(pHead, 2, 100);
	printf("链表第2个元素改为100\n");
	ListTraverse(pHead);
	printf("pHead内容:%x\n", pHead);
	//链表反转
	ListReverse(pHead);
	printf("链表反转:\n");
	ListTraverse(pHead);
	//查找数组中第一个元素3的位置
	printf("第一个元素3的位置为:%d\n", ListLocateElement(pHead, 3));
	//查找链表倒数第3个元素
	PNode p = ListSearchReverseKthNode(pHead, 3);
	printf("链表倒数第3个元素:%d\n", p->data);
	//清空链表
	ListClear(pHead);
	printf("清空链表之后,链表是否为空:%d\n", ListEmpty(pHead));
	printf("pHead内容:%x\n", pHead);
	printf("链表长度:%d\n", ListLength(pHead));

	销毁链表
	ListDestroy(&pHead);
	printf("%d\n", 5);
	//销毁链表之后,就能不在判断链表是否为空了。怎么确认链表是否销毁了
	/*printf("销毁链表之后,链表是否为空:%d\n", ListEmpty(pHead));
	printf("pHead内容:%p\n", pHead);
	printf("链表长度:%d\n", ListLength(pHead));*/

	return 0;
}

 

循环链表

 

带头指针的循环链表示意图

最后一个节点指向的是头结点,不是第一个节点。

带尾指针的循环链表示意图

双向链表

一般都构造双向循环链表,双向循环链表一般都带头结点。

带头结点的双向循环链表示意图:

为空时:

循环链表主要优点:从表中任一结点出发都能遍历整个链表

双循环链表主要优点:方便找到前驱,任意节点都能遍历,方便在链表尾部操作。

//实现一个带头节点和尾指针的单循环链表。定义尾指针而不定义头指针是为了方便两个链表连接

#include<stdio.h>

#define true 1
#define false 0
typedef int bool;

typedef struct Node
{
	int data;
	struct Node *next;
}Node ,*PNode;

//初始化链表
bool InitList(PNode *pTail)
{
	*pTail = (PNode)malloc(sizeof(Node));
	if (!*pTail)
	{
		exit(-1);
	}
	(*pTail)->next = *pTail;
	return true;
}

//求长度
int ListLength(PNode pTail)
{
	int i = 0;
	PNode p = pTail->next;
	while (p != pTail)
	{
		i++;
		p = p->next;
	}
	return i;
}

//第i个位置插入一个元素,尾节点有点烦人,插入和删除的时候,都要注意改变pTail的值
//所以这里要传入*pTail.
bool ListInsert(PNode *pTail, int i, int val)
{
	PNode p = (*pTail)->next;//p指向头结点
	int j = 0;
	/*while (p&&j < i-1)
	{
		p = p->next;
		j++;
	}
	if (!p || j > i - 1)
	{
		return false;
	}*/
	if (i <= 0 || i > ListLength(*pTail) + 1)
		return false;
	while (j < i - 1)
	{
		p = p->next;
		j++;
	}
	PNode q = (PNode)malloc(sizeof(Node));
	q->data = val;
	q->next = p->next;
	p->next = q;
	if (p == (*pTail))
		(*pTail) = q;
	return true;
}

//遍历
void ListTraverse(PNode pTail)
{
	PNode p = pTail->next->next;//p指向第一个元素
	while (p!=pTail->next)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

//删除
bool ListDelete(PNode *pTail, int i, int *val)
{
	PNode p = (*pTail)->next;	//	p指向头结点
	int j = 0;
	//while (p&&j < i - 1)//不要这样判断很烦,容易出错
	//{
	//	p = p->next;
	//	j++;
	//}
	//if (!p || j > i - 1)
	//{
	//	return false;
	//}
	if (i <= 0 || i > ListLength(*pTail))
	{
		printf("删除元素位置不正确\n");
		return false;
	}
		
	while (j < i - 1)
	{
		p = p->next;
		j++;
	}

	PNode q = p->next;
	*val = q->data;
	p->next = q->next;
	if (q == *pTail)//删除的是表尾元素
		*pTail = p;
	free(q);
	return true;
}

int main(void)
{
	PNode pTail;
	//初始化链表
	InitList(&pTail);
	//插入元素
	ListInsert(&pTail, 1, 1);
	ListInsert(&pTail, 1, 2);
	ListInsert(&pTail, 1, 3);
	ListInsert(&pTail, 1, 4);
	ListInsert(&pTail, 1, 5);
	//遍历链表
	ListTraverse(pTail);
	//删除第5个元素
	int val;
	ListDelete(&pTail,5, &val);
	printf("删除的元素为:%d\n", val);
	//遍历链表
	ListTraverse(pTail);
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值