单链表的实现---增加可选功能

之前上传了一个单链表的博文,但是在实现上交互性较差,而且在给结点分配空间的时候是使用的malloc函数实现的,今天我们就使用c++中的new关键字来给结点分配内存空间。
话不多说,下面就是关于单链表操作的各个功能的函数。

一、用结构体创建一个结点数据类型
为了能够实现单链表的操作,结点里面主要有两部分,一部分是数据域,存放结点的数据值,另一个是指针域,存放下一个结点的地址。

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

在这里LNode就是我们定义的结点类型,同时我们又声明了*LinkList的类型与LNode是保持一致的,本质上两者没有什么不一样。

二、对列表进行初始化

(1)首先是单纯的进行初始化,这就需要我们去声明一个头结点,用头指针L指向头结点,并且用头结点将指针域设置为空。

void InitList(LinkList &L){
	L = new LNode;//生成新结点作为头结点,并且用头指针L指向头结点
	L->next = NULL;//头结点的指针域设置为空

(2)如果想要在初始化的同时就对单链表进行数据的输入,那么这里有两种方式来实现。
第一种方式是尾插法,就是在链表的尾部将数据一个一个地插入进去,具体实现如下:

//用尾插法插入数据
void IniList_R(LinkList &L, int n){
	L = new LNode;	//创建一个新的结点
	L->next = NULL;	//并且将头结点设置为空
	LinkList r;		//声明一个尾指针
	LinkList p;		//声明一个指针p,用于创建新的结点
	r = L;			//对尾指针r初始化
	for (int i=0; i<n; ++i){
		cout<<"请输入第"<<i+1<<"个数据:";
		p = new LNode;
		cin>>p->data;
		p->next = NULL;
		r->next =p;
		r = p;
	}
}

三、上面我们完成了单链表的创建并且初始化传入数据,那么我们现在来写一个输出的函数将链表中的元素进行输出。

//输出链表中的所有数据
void showList(LinkList L){	
	cout<<"链表中的所有元素为:";	

	while(L->next){
		cout<<L->next->data<<" ";
		L = L->next;
	}
	cout<<endl;
}

在这里实际上就是对链表进行了一个遍历,同时需要注意形参是安置传递的,有很多同学往往在这里会按地址传递,导致在程序运行的过程中报错,原因在于当遍历完链表之后,头指针就移动到尾部,此时的链表实质上是一个空表。

四、求单链表的长度
单链表的长度实质上也是对链表进行了一个遍历,只是在遍历的时候对元素的个数进行了统计,具体代码如下。

//求链表的长度
int getLength(LinkList L){
	int len = 0;
	while(L->next){
		len++;
		L=L->next;
	}
	return len;
	//cout<<"链表的长度为:"<<endl;
}

其实这里的函数也可以是无返回类型的,就是上面代码注释掉的地方。因为在后面的函数中要使用到这个函数,所以在这里我就定义为int返回类型的函数。

五、插入数据
下面这段代码就是实现单链表的插入,包括了三个形参,第一个是单链表的头指针,注意这里是按地址传递,第二个参数就是位置,第三个参数就是要插入元素的值。

//插入数据
void insertElem (LinkList &L, int i, int e) {
    
	LinkList p = L;
	int j = 0;
	while(p && (j < j-1)){
		p = p->next;
		++j;
	}
	if(!p || j>i-1){
		cout<<"输入位置有误!"<<endl;
	}
	LinkList s = new LNode;
	s->data = e;
	s->next = p->next;
	p->next = s;
}

六、删除数据
这里删除数据有两种方式,一种是按照元素的值来删除数据,第二种是按照位置来删除数据。
在删除数据的时候,我们进行判断链表的长度是否为0,也就是链表中是否有元素。
首先是按照元素的值来删除数据。

//按值删除数据
void deleElem_Elem(LinkList &L, int x) {   //删除值为x的结点(链表无重复值)
   if (getLength(L) <= 0) {
        cout << "表空,没有元素可删除" << endl;
		return;
    }
 
    LinkList p;
	LinkList q;
    p= L->next;
	q = L;   //记录ptr的前一个位置的结点
    while (p) {
        if (p->data == x) {
            q->next = p->next;  //把x值的结点的前一个结点的next指向p的next结点
            free(p);  //释放空间
            return;
        }
        q = p;
        p = q->next;
    }
}
下面是按照位置来删除数据。
//按位置删除数据
void deleElem_Loca(LinkList &L, int Loca){
	if (getLength(L) <= 0) {
        cout << "表空,没有元素可删除" << endl;
		return;
    }
	LinkList p;
	LinkList q;
    p= L->next;
	q = L;   //记录ptr的前一个位置的结点
    Loca = Loca - 1;  //因为如果k = 1,直接用q->next = p->next就把p删掉了,所以要减1
    while (Loca-- && p) {
        q = p;
        p = p->next;
    } 
    if (p == NULL || Loca > 0) {
        cout << "要删除的位置不存在" << endl;
    }else {
        q->next = p->next;  //删除ptr结点
        free(p);  //释放空间
    }
}

七、获取数据

//获取数据
int GetElemList(LinkList &L, int i) {    //返回第i个位置的值
    LinkList p = L;
    int k = i;  //标记i的值,以防不存在输出显示
    while (i > 0 && p->next) {
        p = p->next;
        i --;
    }
 
    if (i == 0 && p != NULL) {    //当i == 0 和 ptr 不为空代表找到了第i个位置的元素
        return p->data;
    }else {
        cout << "第" << k << "个位置不存在" << endl;
        return -1;
    }
}

八、清空列表

//清空链表
void ClearList(LinkList &L) {    //清空链表
    LinkList p = L;
    if (getLength(L) > 0) {
        while (p->next) {
           LinkList temp = p->next;
           p->next = p->next->next;
           free(temp);  //释放空间
        }
    }
}

上面我们完成了单链表的基本功能,下面我们来写一个主函数实现对单链表的操作,为了提高可操作性,我写了一个while循环来实现对单链表的选择操作,具体代码如下:

void main(){
	LinkList L;
	

	cout<<"1--输入数据"<<endl;
	cout<<"2--删除数据"<<endl;
	cout<<"3--获取表长"<<endl;
	cout<<"4--输出链表"<<endl;
	cout<<"5--插入数据"<<endl;
	cout<<"6--查找数据"<<endl;
	cout<<"7--清空链表"<<endl;
	cout<<"8--退出程序"<<endl;
	
	while (true){
		cout<<"请输入功能序号:";
		cin>>num;
		if (num == 1){
			cout<<"请输入要输入数据的个数:";
			cin>>num3;
			IniList_R(L,num3); //初始化链表
		}else if (num == 2){
			while (true){
				int num2;
				cout<<"1--按位置删除数据"<<endl;
				cout<<"2--按值删除数据"<<endl;
				cout<<"3--退出删除功能"<<endl;
				cout<<"请输入你要选择的功能:";
				cin>>num2;
				if (num2 == 1){
					int position;
					cout << "请输入要删除的位置: ";
					cin >> position;
					deleElem_Loca(L, position); 
				}else if(num2 == 2){
					int delem;
					cout<<"请输入你要删除的值:";
					cin>>delem;
					deleElem_Elem(L, delem);	//确保链表中没有重复值元素,如果有默认删除第一个出现这个值得元素
				}else if(num2 == 3){
					break;
				}else{
					cout<<"数据输入错误";
					break;
				}
			}
		}else if(num == 3){
			cout<<"表长为:"<<getLength(L)<<endl;
		}else if (num == 4){
			showList(L);
		}else if (num == 5){
			int i, data;
			cout << "请输入要插入的位置和值:";
			cin >> i;
			cin >> data;
			insertElem(L, i, data); 
		}else if (num == 6){
			int n;
			cout << "请输入要查找的位置: ";
			cin >> n;
			if (GetElemList(L, n) != -1)
				cout << "第" << n << "个位置的值为: " << GetElemList(L, n) << endl; 
		}else if (num == 7){
			ClearList(L);
		}else if (num == 8){
			break;
		}else{
			cout<<"非法输入!"<<endl;
		}
	
	}

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DS单链表是一种线性数据结构,它由若干个节点组成,每个节点包括数据域和指针域,其中数据域用于存储数据,指针域用于指向下一个节点。DS单链表的存储结构如下: ``` typedef struct ListNode { int val; struct ListNode *next; } ListNode; ``` 其中,val表示节点存储的数据,next表示指向下一个节点的指针。 DS单链表的基本操作包括:创建、插入、删除、查找、遍历等。 1. 创建 创建DS单链表的方法有多种,例如头插法、尾插法等。其中,头插法的实现代码如下: ``` ListNode* createList(int arr[], int n) { ListNode *head = NULL; for (int i = 0; i < n; i++) { ListNode *node = (ListNode*)malloc(sizeof(ListNode)); node->val = arr[i]; node->next = head; head = node; } return head; } ``` 2. 插入 DS单链表的插入操作包括在指定位置插入节点和在末尾插入节点。其中,指定位置插入节点的实现代码如下: ``` void insert(ListNode *head, int val, int pos) { ListNode *node = (ListNode*)malloc(sizeof(ListNode)); node->val = val; ListNode *p = head; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { return; } node->next = p->next; p->next = node; } ``` 3. 删除 DS单链表的删除操作包括删除指定位置的节点和删除指定值的节点。其中,删除指定位置的节点的实现代码如下: ``` void delete(ListNode *head, int pos) { ListNode *p = head; ListNode *q = NULL; for (int i = 1; i < pos && p != NULL; i++) { q = p; p = p->next; } if (p == NULL) { return; } if (q == NULL) { head = head->next; } else { q->next = p->next; } free(p); } ``` 4. 查找 DS单链表的查找操作包括查找指定位置的节点和查找指定值的节点。其中,查找指定值的节点的实现代码如下: ``` ListNode* find(ListNode *head, int val) { ListNode *p = head; while (p != NULL) { if (p->val == val) { return p; } p = p->next; } return NULL; } ``` 5. 遍历 DS单链表的遍历操作包括正向遍历和反向遍历。其中,正向遍历的实现代码如下: ``` void traverse(ListNode *head) { ListNode *p = head; while (p != NULL) { printf("%d ", p->val); p = p->next; } } ``` 以上就是DS单链表的存储结构与操作的介绍。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值